TS
- 基本数据类型(boolean, number, string; 数组,元组,枚举; undefined, null; any, void; never;object)
- 元组类型
let tuple: [string, number, boolean]; tuple = ['a', 1, true]; // 长度必须跟定义时的一致,每个元素也要跟定义时的一一对应
-
- 枚举类型
// 没有指定序号 enum Role { SUPER_ADMIN, ADMIN, USER } console.log(Role.SUPER_ADMIN) // 0 console.log(Role.ADMIN) // 1 console.log(Role.USER) // 2
// 指定序号 enum Role { SUPER_ADMIN = 8, ADMIN = 9, USER =1 } console.log(Role.SUPER_ADMIN) // 8 console.log(Role.ADMIN) // 9 console.log(Role.USER) // 1
// 不从头指定序号 enum Role { SUPER_ADMIN, ADMIN = 9, USER } console.log(Role.SUPER_ADMIN) // 0 console.log(Role.ADMIN) // 9 console.log(Role.USER) // 10(递增的结果)
// 由序号找到对应的枚举值 enum Role { SUPER_ADMIN = 8, ADMIN = 9, USER =1 } console.log(Role[8]) // SUPER_ADMIN console.log(Role[9]) // ADMIN console.log(Role[1]) // USER
-
- never类型
// 1. 报错函数的返回类型 const errorFunc = (str: string): never => { throw new Error(str); } // 2. 死循环 const infiniteFunc = () : never => { while(true) {} }
never类型是其他任何类型的子类型,可以将never类型值赋给其他类型。
let neverVal = (() => { while(true) {} })(); //neverVal 是 never 类型
let num: number = neverVal; // 不会报错
2. 类型断言
let getLength = (target: string | number) => { if ((target as string).length || (target as string).length === 0) { return (target as string).length; } return target.toString().length; }
// 例子中参数是联合类型,如果不使用类型断言,橘色部分的target变量会被TS判断为没有length属性而报错;只有再使用的时候将其断言为string类型,才可消除报错
3. 接口混合
下面这个例子定义了一个计数器,没有将其定义为全局变量( 避免被污染)。
interface Counter { (): counter; count: number; } // 注意:这里是返回值是Counter类型 const getCounter = (): Counter => { const c = () => { c.count++; }; c.count = 0; return c; } const counter: Counter = getCounter(); counter(); console.log(counter.count); // 1
4. 类型别名 type
type IString = string; // 定义后可以在其他地方使用IString声明变量,等同string type AddFunction = (num1: number, num2: number, num3?: number) => number // 函数类型的类型别名
let addFunction: AddFunction;
addFunction = (num1: number, num2: number) => num1 + num2;
addFunction = (num1: number, num2: number, num3: number) => num1 + num2 + num3;
- 类型别名type 与 接口interface的区别:
- 一般情况下,通过interface定义的类型,可以使用type达到同样的效果(注意type定义时要加 = )。
- interface可以通过extends进行扩展,type 通过 & 进行扩展
- 可以通过定义同名接口为现有类型增加字段,而type不可以同名
type Point = {
x: number;
y: number;
};
type SpecialPoint = Point & {
name: string;
}
interface Point {
x: number;
Y: number;
};
interface SpecialPoint extends Point {
name: string;
}
- 函数
- 函数参数默认值
let addFunc = (x: number, y = 3) => x+3; console.log(addFunc(1)); // 4 console.log(addFunc(4, 5)); // 9 console.log(addFunc(4, 'a')); // 报错,第二个参数只能是number类型值
-
- 函数剩余参数
let funct1 = (arg1: number, ...args: number[]): number => { // .... }
-
- 函数重载(只能使用function进行重载类型的定义,不能使用interface或者type)
// 函数重载类型声明 function handleFunc (arg1: string) : string[]; function handleFunc (arg1: number) : number[]; // 函数实体定义 function handleFunc(arg1: any): any[] { if (typeof arg1 === 'string) { return arg1.split(''); } else if (typeof arg1 === 'number') { return arg1.toString().split('').map(item => Number(item)); } }
- 泛型
const getArray = (value: any, times: number) : any[] => { return new Array(times).fill(value); }; // 1. value 是string类型,且对得到的数组进行处理 console.log(getArray('abc', 2).map(item => item?.length)); // [3,3]; // 2. value 是number类型,number上没有length属性,但TS并没有给我们提示 console.log(getArray(4, 2).map(item => item?.length)); // [undefined, undefined]
为了解决上述问题,引入泛型。
const getArray = <T>(value: T, times: number) : T[] => { return new Array(times).fill(value); } console.log(getArray<number>(4, 2).map(item => item?.length)); // 此时, 由于泛型变量的存在,TS得知getArray返回值是一个number类型的数组,在item取length属性时会报错。
在定义函数时,可以使用多个泛型变量来帮助我们更好地定义类型。
const getTupleArray = <T, U>(param1: T, param2: U, times: number): [T, U][] => { return new Array(times).fill([param1, param2]); } console.log(getTupleArray<number, string>(4, 'abc', 2)); // [[4, 'abc'], [4, 'abc']] 返回的是元组类型的数组
利用泛型定义函数的类型
let getArrayFunc = <T>(arg: T, times: number) => T[]; getArrayFunc = (arg: any, times: number) => { return new Array(times).fill(arg); } // 虽然在定义函数实体时,我们使用了any定义参数类型,但由于的函数类型定义时使用了泛型,所以TS会判断出得到的数组类型是number[], 调用length时报错 getArrayFunc(6, 2).map(item => item.length);
利用类型别名与泛型来定义函数类型
type getArrayFunc = <T>(arg: T, times: number) => T[] let getArrayFunc = (arg: string, times: number) => { return new Array(times).fill(arg); } getArrayFunc('cc', 3).forEach(item => { console.log(item.length); } // 2 // 2 // 2
利用接口和泛型定义函数类型
// 在外层定义的泛型变量, 在接口里面任何位置都能取到 interface getArray<T> { (arg: T, times: number) => T[]; count: T; }
- 泛型约束
// 使泛型变量T必须具备length属性 interface ValueWithLength { length: number; } const getArray = <T extends ValueWithLength>(arg: T, times: number): T[] => { return new Array(times).fill(arg); } // 类型本身有length属性,或者对象有length属性 getArray('ad', 2); getArray([2,3], 3); getArray({ length: 6 }, 4); getArray(2, 3); // 2没有length属性,报错
泛型约束与索引的联合使用
let obj = { 'a': 'a', 'name'; 'cc' }; // keyof T,得到泛型T上面所有key组成的数组 const getProp = <T, K extends keyof T>(obj: T, propName: K) => { return obj[propName]; } getProp(obj, 'a'); // a getProps(obj, 'b'); // 报错
- 文字断言
// 调用priteByFormat 时第二个参数只能是 ‘left’ | ‘right’ | ‘center’中的一个,不能是其他的值。 function priteByFormat(str: string, alignment: ‘left’ | ‘right’ | ‘center’){ } // 函数返回值是数字文字类型 function compare(a: string, b: string): 0 | -1 | 1 { return a === b ? 0 : a > b ? 1 : -1; } // 布尔文字类型 const text1: true = true; // 只能赋true, 不能赋false或其他值 const text2: false = false; // 只能赋false, 不能赋true或其他值
// 类型推断 function request(url: string, method: ‘GET’ | ‘POST’ | ‘HEADER’) { } const obj = { url: ‘http: ilove.china.com’, method: ‘GET’ }; request(obj.url, obj.method)// 调用时,obj.method会因自动类型推断(推断为string类型)错误而报错 // 解决方法: 在任意位置添加类型断言 const obj = { url: ‘http: ilove.china.com’, method: ‘GET’ as ‘GET’ };