童装网站建设目标,网站开发一般多钱,公司文化墙设计方案,淘宝免费推广的方式有哪些目录 引入认识特点安装使用变量声明类型推导 JS 和 TS 共有类型number类型boolean类型string类型Array类型null和undefined类型object类型symbol类型对象类型函数类型 可选和只读type 和 interface索引签名类型断言非空类型断言类型缩小严格赋值检测现象TS 新增类型字面量类型a… 目录 引入认识特点安装使用变量声明类型推导 JS 和 TS 共有类型number类型boolean类型string类型Array类型null和undefined类型object类型symbol类型对象类型函数类型 可选和只读type 和 interface索引签名类型断言非空类型断言类型缩小严格赋值检测现象TS 新增类型字面量类型any类型unknown类型void类型never类型tuple类型联合类型交叉类型枚举类型泛型映射类型条件类型 类型体操模块-声明-配置 引入
随着近几年前端领域的快速发展让JavaScript迅速被普及和受广大开发者的喜爱借助于JavaScript本身的强大也让使用JavaScript开发的人员越来越多JavaScript正在慢慢变好但是直到今天JavaScript在类型检测上依然是毫无进展
类型问题 去实现一个核心类库时如果没有类型约束那么需要对别人传入的参数进行各种验证来保证代码的容错率 去调用别人的函数对方没有对函数进行任何的注释只能去看里面的逻辑来理解这个函数需要传入什么参数 返回值是什么类型 如果可以给JavaScript加上很多限制在开发中就可以很好的避免这样的问题了
为了弥补JavaScript类型约束上的缺陷很多公司推出了自己的方案
2014年Facebook推出了flow来对JavaScript进行类型检查同年Microsoft微软也推出了TypeScript1.0版本
TypeScript使用率 Vue2.x的时候采用的就是flow来做类型检查 Vue3.x已经全线转向TypeScript98.3%使用TypeScript进行了重构 Angular在很早期就使用TypeScript进行了项目重构并且需要使用TypeScript来进行开发 最流行的编辑器VSCode也是使用TypeScript来完成的 在React中已经使用的ant-design的UI库也大量使用TypeScript来编写
学习TypeScript不仅仅可以为我们的代码增加类型约束而且可以培养前端程序员具备类型思维
认识
TypeScript在GitHub和官方上对自己的定义 GitHub说法TypeScript is a superset of JavaScript that compiles to clean JavaScript output TypeScript官网TypeScript is a typed superset of JavaScript that compiles to plain JavaScript 翻译TypeScript是拥有类型的JavaScript超集它可以编译成普通、干净、完整的JavaScript代码
特点 始于JavaScript归于JavaScript 使用现有的JavaScript代码包括流行的JavaScript库并从JavaScript代码中调用TypeScript代码 TypeScript可以编译出纯净、 简洁的JavaScript代码并且可以运行在任何浏览器上、Node.js环境中和任何支持ECMAScript3或更高版本的JavaScript引擎中 TypeScript是一个强大的工具用于构建大型项目 在语言层面上不仅仅增加了类型约束而且包括一些语法的扩展比如枚举类型Enum、元组类型Tuple等 类型允许JavaScript开发者在开发JavaScript应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构 类型是可选的类型推断让一些类型的注释使你的代码的静态验证有很大的不同。类型让你定义软件组件之间的接口和洞察现有JavaScript库的行为 拥有先进的 JavaScript JavaScript所拥有的特性TypeScript全部都是支持的并且它紧随ECMAScript的标准 TypeScript在实现新特性的同时总是保持和ES标准的同步甚至是领先 并且TypeScript最终会被编译成JavaScript代码所以并不需要担心它的兼容性问题在编译时也可以不借助于Babel这样的工具
安装使用 TypeScript的环境安装依赖Node先保证电脑上有Node和NPM环境 npm install typescript -g安装 tsc --version查看版本 项目通常使用webpack配置本地的TypeScript编译环境和开启一个本地服务可以直接运行在浏览器上这个在webpack中学习 我们练习中就简单使用先写ts文件最后要写export {} 是用来声明一个模块的告诉 TypeScript 当前文件是一个模块不是一个全局脚本文件避免命名冲突 然后执行 tsc 文件名 编译成js代码编译后的代码要把exports代码注释在html引入js文件在浏览器查看结果
变量
声明
在TypeScript中定义变量需要指定标识符的类型 声明了类型后TypeScript就会进行类型检测声明的类型可以称之为类型注解Type Annotation var/let/const 标识符: 数据类型 赋值
类型推导
有时候为了方便并不会在声明每一个变量时都写上对应的数据类型TypeScript会在一个变量第一次赋值时根据后面的赋值内容的类型来推断出变量的类型
如果是 const 变量赋值是一个常量字面量它会推导为字面量类型。如果是 let则推导为更宽泛的类型如 number、string赋值为不同类型还是会报错let message hello ts // string类型
message 123 // 会报错 不能将类型“number”分配给类型“string”let flag true // boolean类型const age 18 // 字面量JS 和 TS 共有类型
number类型 数字类型是我们开发中经常使用的类型TypeScript和JavaScript一样不区分整数类型int和浮点型double统一为number类型 ES6新增了二进制和八进制的表示方法而TypeScript也是支持二进制、八进制、十六进制的表示
let num: number 10
num 18
num 18.8
num 100 // 十进制
num 0b110 // 二进制
num 0o555 // 八进制
num 0xf23 // 十六进制boolean类型
boolean类型只有两个取值true和false
let flag: boolean true
flag false
flag 20 30string类型
string类型是字符串类型可以使用单引号或者双引号表示也支持ES6的模板字符串来拼接变量和字符串
let message: string hello
let n: string ts
message hello ${n}Array类型
数组类型的定义有两种方式 下面都表示数组元素必须是string
Arraystringstring[]
let arr1: string[] [abc,cba]
let arr2: Arraystring [cba,abc]
arr1.push(ddd)
arr2.push(eee)
arr1.push(123) // 报错Argument of type number is not assignable to parameter of type string
arr2.push(true) // 报错 Argument of type boolean is not assignable to parameter of type stringnull和undefined类型
在 JavaScript 中undefined 和 null 是两个基本数据类型。 在TypeScript中它们各自的类型也是undefined和null也就意味着它们既是实际的值也是自己的类型
let nu: null null
nu {} // Type {} is not assignable to type null
let un: undefined undefined
un 0 // Type 0 is not assignable to type undefinedobject类型 object描述的是所有非原始值的类型即不包括 string、number、boolean、symbol、null 和 undefined 使用 object 类型时无法直接访问属性因为 TypeScript 并不知道对象的具体结构
let obj: object { name: John };
console.log(obj.name); // 错误属性 name 不存在于 object 类型上
obj { key: value }; // 正确
obj [1, 2, 3]; // 正确
obj function() {}; // 正确
obj string; // 错误不能将 string 赋值给 objectsymbol类型
Symbol 是一种基本数据类型它代表独一无二且不可变的值。它最常用于对象属性的键值保证每个 Symbol 都是唯一的防止属性名冲突
let sym1: symbol Symbol();
let sym2: symbol Symbol(description);console.log(sym1 sym2); // false两个 Symbol 值是唯一的对象类型
具体学习这篇文章待后面补充
函数类型
具体学习这篇文章待后面补充
可选和只读 可选可选属性意味着该属性可以有也可以没有属于非必须的属性。如果没有赋值这个属性的值为 undefined在属性的后面添加一个 ?表示 let bar: {name: string, age: number} {name: obj,age: 18,
}function getInfo(data: {name: string, age: number, height?: number}) {console.log(data)
}
getInfo(bar) // 如果height不是可选的就会报错说bar缺少属性只读只读属性意味着该属性一旦赋值之后就无法修改。通常用于防止对象的某些属性在对象初始化后被改变在属性的前面加 readonly 表示 function getInfo(data: {name: string, readonly age: number, height?: number}) {console.log(data.age)data.age 18 // 会报错
}可选可以结合只读 type Person {readonly id?: number; // 可选且只读属性name: string;
};const person: Person { name: Alice };// 合法因为 id 是可选的
const personWithId: Person { id: 1, name: Bob };// 错误因为 id 是只读属性不能修改
// personWithId.id 2; // Error: Cannot assign to id because it is a read-only property.type 和 interface type 新类型名 现有类型定义类型别名通过类型别名可以将复杂的类型定义抽象为一个更简单的名字并在代码中反复使用可以用于基础类型、对象类型、联合类型、数组、函数等各种类型 type UserType {name: string;age?: number;readonly height: number
};let user: UserType {name: Alice,height: 188,
};interface接口是一种用于定义对象、函数、类等结构的方式 interface IUser {name: string;age?: number;readonly height: number
}let user: IUser {name: Alice,height: 188,
};两者区别 区别一type 类型使用范围更广而 interface 主要用于定义对象的形状 区别二同名接口可以合并声明合并如果两个地方声明了同名的接口TypeScript 会将它们的成员自动合并到一个接口中 interface ILocal {x: numbery: number
}interface ILocal {z: number
}const local: ILocal { // 会合并必须包含xyzx: 100,y: 200,z: 300
}区别三接口可以继承一个或多个其他接口使得多个接口可以共享相同的属性和方法定义 interface IAdult {name: string,age: number
}interface IWorker {working: () void
}interface ICoder extends IAdult, IWorker {eatting: () void
}const student: ICoder {name: coder,age: 16,working() {console.log(working)},eatting() {console.log(eatting)}
}区别四类可以通过 implements 关键字来实现接口保证类中定义了接口所要求的所有属性和方法具体学习这篇文章待后面补充
索引签名
具体学习这篇文章待后面补充
类型断言
类型断言Type Assertions用于明确地告诉编译器某个值的类型而不是让编译器自动推断类型类型断言不会做类型转换它只是在编译时进行静态检查帮助你绕过编译器的类型检查限制
语法 尖括号语法 let someValue: any this is a string;
let strLength: number (stringsomeValue).length;as语法 在使用 JSX 的时候不能使用尖括号语法必须使用 as 语法 let someValue: any this is a string;
let strLength: number (someValue as string).length;使用时机 当 TypeScript 无法自动推断类型时 比如使用第三方库返回的 any 类型数据或者处理一些复杂的联合类型时类型断言可以帮你明确告诉 TypeScript 某个值的具体类型 在联合类型中确定某个具体类型 在联合类型中你可以使用类型断言将值断言为更具体的类型 DOM 元素类型断言 在访问 DOM 元素时TypeScript 可能无法准确推断类型。你可以使用类型断言来告诉 TypeScript 你知道元素的确切类型提示方法更友好 const inputElement document.getElementById(input) as HTMLInputElement;
inputElement.value Hello, World!;限制 类型断言并不会改变数据的实际类型而是让 TypeScript 编译器“信任”你给出的类型。因此错误的类型断言可能导致运行时错误 let someValue: any hello;
let num: number someValue as number; // 这不会在编译时报错但会导致运行时错误类型断言不能断言为不相关的类型例如你不能将一个 string 类型断言为 number 类型 let someValue: any hello;
let num: number someValue as number; // 无效的断言编译时不会报错但运行时可能有问题非空类型断言
允许开发者告诉编译器某个表达式不会为 null 或 undefined它通过在表达式后面加上 ! 操作符实现 使用 基本使用如果某个 DOM 元素可能为 null但我们知道在使用时它肯定已经存在可以使用非空断言 const element document.getElementById(myElement);
console.log(element!.innerHTML); // 使用 ! 断言告诉 TypeScript 这里 element 不会是 null函数中的非空断言 假设你有一个函数返回可能是 null 或 undefined 的值但你确定在某个情况下这个函数一定会返回一个有效值 function getValue(): string | undefined {return Hello;
}const value getValue();
console.log(value!.toUpperCase()); // 使用 ! 断言忽略 undefined 检查联合类型中的非空断言 对于联合类型中的 null 或 undefined你也可以使用非空断言 function processValue(value: string | null) {console.log(value!.toUpperCase()); // 告诉编译器 value 绝对不会为 null
}processValue(Hello); // 安全
processValue(null); // 会在运行时抛出错误因为实际上值为 null注意 非空断言不会在运行时进行检查非空断言只是为了告诉编译器在这个地方忽略 null 或 undefined 的检查但如果你使用非空断言的地方值实际为 null 或 undefined仍然会在运行时抛出错误 应谨慎使用过度使用非空断言可能隐藏代码中的潜在错误。只有在你 非常确定 某个值不会为 null 或 undefined 时才应该使用这个操作符
类型缩小
类型缩小通过各种类型守卫来帮助 TypeScript 更精确地推断出变量的类型从而提高代码的安全性和开发体验。主要缩小方式包括typeof、instanceof、in、平等缩小、!等等 typeof function printID(id: number | string) {if (typeof id string) {console.log(id.length, id.split( ))} else {console.log(id)}
}平等缩小、! type localType up | down | left | right
function getLocal(local: localType) {if(local up) {console.log(向上走)}
}instanceof function formatDate(date: string | Date) {// if(typeof date string) {// console.log(date)// }else {// console.log(date.getTime())// }if(date instanceof Date) { // 判断date是不是Date的实例console.log(date.getTime())}else {console.log(date)}
}in操作符 interface ISwim {swim: () void
}interface IRun {run: () void
}function move(animal: ISwim | IRun) {if (swim in animal) {animal.swim()} else if (run in animal) {animal.run()}
}严格赋值检测现象
对于对象的字面量赋值在TypeScript中有一个非常有意思的现象我们看下面例子在例子中发现换一种赋值的方式多余的属性不会报错
type TTest {name: string, age: number, height: number}
const tt {name: tt,age: 28,height: 188,
}
const test1: TTest tt // 会报错没问题interface ITest {name: string,eatting: () void
}
const it {name: it,age: 18,eatting: function(){}
}
// 方式一
const test2: ITest {name: it,age: 18, // 多的会报错eatting: function(){}
}
// 方式二
const test3: ITest it // 多了age属性不会报错上面现象解释引入TypeScript成员在GitHub的issue中的回答
翻译理解一下 每个对象字面量最初都被认为是 新鲜的fresh 当一个新的对象字面量分配给一个变量或传递给一个非空目标类型的参数时对象字面量指定目标类型中不存在的属性是错误的 当类型断言或对象字面量的类型扩大时新鲜度会消失
TS 新增类型
字面量类型
它允许将变量的类型限定为特定的值字面量类型可以是字符串、数字、布尔值、null、undefined、bigint、symbol 等通过字面量类型你可以让变量的值更加精确 使用 单独使用使用const定义变量时类型推测就为字面量类型 const abc abc // 这时abc就是为‘abc’的字面量类型
const data { // 这时data就是为对象的字面量类型url: http://localhost:8080,method: post
}字符串字面量类型结合联合类型 let direction: left | right | up | down;direction left; // 正确
direction right; // 正确
direction forward; // 错误forward 不在定义的字面量类型之中数字字面量类型结合联合类型 let option: 1 | 2 | 3;option 1; // 正确
option 4; // 错误因为 4 不在数字字面量类型的范围内布尔字面量类型结合联合类型 let isOpen: true | false;isOpen true; // 正确
isOpen false; // 正确推理 /* const data {url: http://localhost:8080,method: post
}type methodType get | post
function request(url: string, method: methodType) {console.log(method)
}
request(data.url, data.method) */
/* 上面的 data.method 会报错Argument of type string is not assignable to parameter of type methodType因为 data.method 推测出的是string类型不能赋值给字面量类型所以我们要明确写明 data.method 是个字面量类型解决方法一类型断言明确告诉它data.method为post字面量类型request(data.url, data.method as ’post‘)二const data {url: http://localhost:8080,method: post} as const
*/type methodType get | post
// 方式一
const data1 {url: http://localhost:8080,method: post
}
function request1(url: string, method: methodType) {console.log(method)
}
request1(data1.url, data1.method as post) // 类型断言data.method为post字面量类型// 方式二
/* as const是一个断言操作符它用于将一个对象或数组的所有属性或元素转换为字面量类型相当于变成了常量对象const data2: {readonly url: http://localhost:8080,readonly method: post} {url: http://localhost:8080,method: post}
*/
const data2 {url: http://localhost:8080,method: post
} as const
function request2(url: string, method: methodType) {console.log(method)
}
request2(data2.url, data2.method)应用 参数和请求方法限制字面量类型通常与联合类型一起使用用于限制函数参数的值只能是特定的字面量 状态管理在状态管理中字面量类型可以用来确保状态值总是一个指定的值 配置项限制当某个配置项需要限定特定值时可以使用字面量类型
any类型
在某些情况下确实无法确定一个变量的类型并且可能它会发生一些变化这个时候可以使用any类型 可以对any类型的变量进行任何的操作包括获取不存在的属性、方法 给一个any类型的变量赋值任何的值比如数字、字符串的值 对于某些情况的处理过于繁琐不希望添加规定的类型注解或者在引入一些第三方库时缺失了类型注解这个时候我们可以使用any
let a: any 123
a 123
a null
a undefined
a truelet aArr: any[] [123, 123, true, null]unknown类型
unknown是TypeScript中比较特殊的一种类型它用于描述类型不确定的变量
和any类型有点类似但是unknown类型的值上做任何事情都是不合法的
let a: any 123
a 123
a null
a undefined
a true
console.log(a.length) // 不会报错let uk: unknown 123
uk 123
uk null
uk undefined
uk true
console.log(uk.length) // 会报错 uk is of type unknownif(typeof uk string) { // 只有当类型范围缩小时再操作才不会报错console.log(uk.length)
}void类型
void通常用来指定一个函数是没有返回值的那么它的返回值就是void类型 当基于上下文的类型推导Contextual Typing推导出返回类型为 void 的时候并不会强制函数一定不能返回内容可以返回任何类型 如果明确写了函数返回值为void类型时函数只可以返回undefined void变量可以赋值 undefined但除了函数返回之外void 通常不被使用
let unused: void undefined; // 虽然可以赋值 undefined但除了函数返回之外void 通常不被使用
function foo1() { // void类型console.log(123)
}
function foo2(): void {console.log(123)return undefined // 只能返回undefined返回其他值会报错
}never类型
never 类型表示那些永远不会存在值的类型。这种类型通常出现在以下几种情况下 函数永远不会返回值 当一个函数永远不会成功执行到结束它会抛出错误或导致程序退出这样的函数返回类型是 never。比如死循环或者抛出异常的函数 不可达的代码 当代码逻辑到达某个永远不可能发生的分支时可以用 never 来标记这类情况
function throwError(message: string): never {throw new Error(message);
}function infiniteLoop(): never {while (true) {console.log(This will run forever);}
}function checkType(key: string | number | boolean){switch (typeof key) {case string:console.log(key.length)break;case number:console.log(key)break;// case boolean: // 不加此代码就会报错 Type boolean is not assignable to type never// console.log(!key)// break;default:const type: never key // 那么这么写的意义何在在扩展工具时检测出一些没有处理的case直接报错 Type boolean is not assignable to type never}
}tuple类型
tuple是元组类型很多语言中也有这种数据类型比如Python、Swift等
tuple和数组有什么区别 数组中通常建议存放相同类型的元素不同类型的元素是不推荐放在数组中可以放在对象或者元组中 元组中每个元素都有自己特定的类型根据索引值获取到的值可以确定对应的类型 tuple通常可以作为返回的值在使用的时候会非常的方便 TypeScript 中的元组继承了数组的行为。在 JavaScript 中数组是动态的元素可以随时增加或删除。为了兼容这一点TypeScript 允许通过数组方法往元组中动态添加元素 TypeScript 的元组会检查方法传入的参数类型是否与元组的元素类型兼容。只要你添加的元素类型符合元组定义中的类型就不会有类型错误
let tu: [string, number, boolean, null?] [123, 123, true]
let tu0 tu[0] // tu0就是string类型
tu.push(null)
tu.push(123)
tu.push({}) // 会报错因为元组中没有定义对象// 在函数中使用元组类型是最多的(函数的返回值)
function useState(initialState: number): [number, (newValue: number) void] {let stateValue initialStatefunction setValue(newValue: number) {stateValue newValue}return [stateValue, setValue]
}const [count, setCount] useState(10)
console.log(count)
setCount(100)联合类型
联合类型是由两个或者多个其他类型组成的类型使用 表示表示可以是这些类型中的任何一个值联合类型中的每一个类型被称之为联合成员unions members 传入给一个联合类型的值只要保证是联合类型中的某一个类型的值即可 使用时需要进行类型缩小TypeScript可以根据缩小的代码结构推断出更加具体的类型 可以和字面量类型结合使用
let union: boolean | string 123
union true
function handleUnion(un: boolean | string){console.log(un.length) // 报错if(typeof un string) { // 类型缩小console.log(un.length)}else {console.log(un)}
}
handleUnion(union)// 结合字面量类型
type localType up | down | left | right
function getLocal(local: localType) {if(local up) {console.log(向上走)}console.log(local.length)
}
getLocal(down)
getLocal(123) // 会报错交叉类型
交叉类型使用 符号表示需要满足多个类型的条件
let sn: string number // 这种值肯定是没有的没有意义// 交叉类型应用
type personType { name: string, running: () void }interface IPerson {age: number,jumping: () void
}const info: personType IPerson { // 将多个对象的属性合并name: info,age: 38,running:() {},jumping:() {}
}function getPerson (person: personType IPerson) {console.log(person)
}
getPerson(info)枚举类型
枚举其实就是将一组可能出现的值一个个列举出来定义在一个类型中这个类型就是枚举类型枚举允许开发者定义一组命名常量常量可以是数字、字符串类型 数字枚举是最常见的枚举类型枚举成员的值默认是从 0 开始递增的具有反向映射的特性可以通过枚举的值来获取枚举成员的名字 enum Direction {Up, // 0Down, // 1Left, // 2Right // 3
}let dir: Direction Direction.Up;
console.log(dir); // 输出: 0enum Direction {Up 1, // 1Down, // 2Left, // 3Right // 4
}console.log(Direction.Up); // 输出: 1
console.log(Direction[1]); // 输出: Up 反向取值字符串枚举每个成员必须显式地设置字符串值并且不会进行自动递增不具备反向映射特性 enum Direction {Up UP,Down DOWN,Left LEFT,Right RIGHT
}let dir: Direction Direction.Up;
console.log(dir); // 输出: UP 常量枚举在需要性能优化的场景下你可以使用 const enum 来声明常量枚举会在编译时被完全移除使用枚举成员的地方会被替换成实际的值 const enum Direction {Up,Down,Left,Right
}let dir: Direction Direction.Up;
console.log(dir); // 输出: 0枚举成员分为常量成员constant member和计算成员computed member 常量成员是在编译时计算出值的或者从数字常量初始化的枚举 计算成员是在运行时计算其值的 enum FileAccess {None,Read 1 1, // 常量成员Write 1 2, // 常量成员ReadWrite Read | Write, // 常量成员G 123.length // 计算成员
}枚举本身可以作为一种类型来使用 enum Direction {Up,Down,Left,Right
}function move(direction: Direction) {console.log(direction);
}move(Direction.Left); // 输出: 2泛型
具体学习这篇文章待后面补充
映射类型
具体学习这篇文章待后面补充
条件类型
具体学习这篇文章待后面补充
类型体操
具体学习这篇文章待后面补充
模块-声明-配置
具体学习这篇文章待后面补充