function identity (value:T) : T {return value;
}
其实泛型就是使用字母来代替将要接收的类型,这里的"T"是代表类型的缩写,表示对将要接收类型的一个占位符,占位符可以是任意字母,下面是一些常用的占位符
如果在函数中使用了泛型,那么我们可以在使用的时候指明类型,也可以不显式指明类型
function identity (value: T ,message: U) : T {console.log(message)return value;
}
//不指定泛型变量的实际类型
console.log(identity(20,'动感超人'));//手动指定泛型变量的实际类型
console.log(identity(20,'动感超人'))
假如我们在html当中引入了jquery插件,那么就会在全局当中增加一个关键字$
,此时如果我们在ts文件当中的书写关键字$
就会发现ts会提示找不到$,ts2304
,也就是说ts不认识这个全局变量$
所以我们可以使用declare
来定义这个全局变量declare const $ = xxxx
,这样子ts就认识这个全局变量$了
注意点
declare
声明不包含具体的实现,也就是说我们只是声明,不做具体处理declare和一些声明文件查询:@地址
Math
,JSON
,Object
这些全局对象呢?那是英文typescript已经在文件当中声明了node_modules/vite/client.d.ts
当中就可以看到declare的声明,部分代码如下declare module '*.module.css' {const classes: CSSModuleClassesexport default classes
}
// CSS
declare module '*.css' {const css: stringexport default css
}
// images
declare module '*.jpg' {const src: stringexport default src
}
//如果vite不declare,那么就会提示找不到模块"./file.css"/或其相应的类型声明
import css from "./file.css";//如果vite不declare,那么就会提示找不到模块"./abao.jpg"或其相应的类型声明
import logo from "./abao.jpg";
any
:我不在于它的类型
unknown
:我不知道它的类型(可以理解为类型安全的any),使用了unknown,必须要自己进行类型检测后才可以对变量进行操作,否则会报警告或错误
对于下列函数,如果是使用any
类型,是不会有任何报错提示的
function invokeCallBack(callback:any){try {callback();}catch (e){console.log(e)}
}
invokeCallBack(1)
unknown
,则会提示TS2571: Object is of type 'unknown'.
function invokeCallBack(callback:unknown){try {//TS2571: Object is of type 'unknown'.callback();}catch (e){console.log(e)}
}
invokeCallBack(1)
function invokeCallBack(callback:unknown){try {if(typeof callback === 'function'){callback();}}catch (e){console.log(e)}
}
invokeCallBack(1)
//Type 'string' is not assignable to type 'never'
let num: never = 123;//Type 'string' is not assignable to type 'never'
let name: never = '超人';
interface
接口定义对象类型,可以使用extends进行扩展interface Vector1D {x:number}//等同于interface Vector3D {x:number,y:number,}
interface Vector2D extends Vector1D {y:number}//等同于interface Vector3D {x:number,y:number,z:number}
interface Vector3D extends Vector2d {z:number};
type Point = {x: numbery:number
}
type SetPoint = (x:number,y:number) => void;
interface Point {x: number;y: number; // ";" 或则 "," 或者不写都可以
}
interface SetPoint {(x: number, y: number): void;
}
&
交叉运算符进行合并运算,注意,交叉类型中的交叉,并不是指两个类型的交集,而是并集interface
//类型别名通过交叉运算符来扩展
type Animal = {name: string;
};
type Bear = Animal & {honey: boolean;
};
const bear: Bear = {name: "熊大",honey: false,
};
// 接口通过extends来扩展
interface Animal {name: string;
}
interface Bear extends Animal {honey: boolean;
}
const bear: Bear = {name: "熊大",honey: false,
};
extends
关键字来继承,类型也只支持使用&
来完成扩展type Animal = {name: string;
};
interface Bear extends Animal {honey: boolean;
}
const bear: Bear = {name: "熊大",honey: false,
};
interface Animal {name: string;
}
type Bear = Animal & {honey: boolean;
};
const bear: Bear = {name: "熊大",honey: false,
};
type MyNumber = number; //基本类型定义别名
type StringOrNumber = string | number; //联合类型定义别名
type Point = [number, number]; //元组类型定义别名
interface User {name: string;
}
interface User {age: number;
}
let user: User = {name: "李白",age: 1000,
};
user.name; //李白
user.age; //1000
type User = {name: string;
};
//标识符“User”重复。ts(2300)
type User = {age: number;
};
使用类型别名的场景
使用接口的场景
有时候我们可能会想这样子,我想规定一个对象类型的key只能为字符串,值是任意的,那么要怎么做呢?可以使用索引签名
格式语法如下
{[key:KeyType] : ValueType}
string
,number
,symbol
,不能为字面量类型或者是泛型类型,如需要使用字面量或泛型,则需要使用Record内置工具类型
//比如下面
interface selfName1 {[key:string] : string
}
const test1:selfName1 = {name:'李白',hobby:'吃饭',
}const selfName2:{[key:string] : string} = {name:'李白',hobby:'吃饭',age:1000,//报错,警告
}
KeyType
只能为string
或者 number
或者symbol
不能为其他的值//错误的keyType
interface selfName3 {//keytype只能为string,number,symbol[key:boolean] : string
}
interface Options {[key:string]:string | number | boolean,timeout:number,//已知的键
}
const option:Options = {timeout:1000,errorMessae:'The request timed out!',isSuccess:false,
}
interface PropChangeHandler {[key:`${string}Changed`]: () => void;
}let handlers:PropChangeHandler = {idChanged: () => {},nameChanged: () => {},//报错,因为后面少了一个字符"d",和规定的type不相同ageChange: () => {},
}
type User1 = {//报错 索引签名类型参数不能为字面量类型或者是泛型类型[key:"id"]:string,
}type User2 = {
//报错 索引签名类型参数不能为字面量类型或者是泛型类型[key:"id" | "name"] :string
}//有人可能会有疑问,说,哎呀,这个为什么可以
interface PropChangeHandler {//这个没问题,因为这个不是字面量啊[key:`${string}Changed`]: () => void;
}
type User3 = Record<"id", string>
const a:User3 = {id:'2tjawjtiaowt',
}type User4 = Record<'id' | 'name', string>;
const b:User4 = {id:'2tjawjtiaowt',name:'动感超人'
}
Pick
,就是从某一个类型当中挑选一部分//K extends T 泛型约束的语法,用于约束泛型K类型
type Pick = {[P in K]:T[P]
}
//用js来解释就是
function Pick (obj,keys) {const result = {};for(const key of keys){result[key] = obj[key]''}return result;
}
Object.keys
函数作用,Object.keys
会返回对象身上所有可枚举key组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。const object1 = {a: 'somestring',b: 42,c: false
};console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]
keyof
也是,返回对象身上key值组成的联合类型class Person {year:number = 2022;hobby:string = '吃饭';
}
//等同于 type P0Types = 'year' | 'hobby'
type P0Types = keyof Person;
const P01:P0Types = 'year';
const P02:P0Types = 'hobby';interface Person1Inter {id:number,name:string,
}
//等同于 type P1Types = 'id' | 'name'
type P1Types = keyof Person1Inter;
const P11:P1Types = 'id';
const P12:P1Types = 'name';enum HttpMethods {Get,Post,
}
type Methods = keyof typeof HttpMethods;
const P21:Methods = 'Get';
const P22:Methods = 'Post';
type K1 = keyof boolean ;// ValueOf// "toString" | "toFixed" | "toExponential"
// | "toPrecision" | "valueOf" | "toLocaleString"
type K2 = keyof number;type K3 = keyof any; string | number | symbol
export enum ab {'a','b'
}//uni等同于 'a' | 'b'
type uni = keyof typeof ab
TypeScript 中分“类型”和“值”,类型是 TypeScript 认的,一般编译后会消失(不存在于 JS 中)。枚举是比较特殊的定义,虽然定义成类型,但实际是值,它在编译成 JS 之后是一个对象。
TypeScript 中的枚举还分情况,有数值型枚举,也有字符串型枚举,还有混合型的……不讨论复杂了,这里就说数值型的。
enum Hello {A,B
}type X = keyof Hello;
你猜 X
是什么呢?你会发现它包含 toFixed
和 toPrecision
等,是不是感觉像是个 Number 类型的 Key 呢?
再来看看 Number 类型的 …… 果然一样
如果不加
Exclude
运算,会看到keyof Number
看不到键列表
想想,实际上也是,如果这样使用
const a: Hello = Hello.A;
a
的值实际上是一个 Number(仅数值型枚举的情况)
所以 TypeScript 中需要使用 typeof Hello
来取实际的枚举类型(不然就是 Number 的子类型),实际上它是一个接口。
这个类型取出来之后,枚举值名称是被当作类型的 Key 的,所以可以用 keyof
把键值取出来。
ts的映射个人觉得有点像是js当中的map吧,操作都是传入a,经过处理后返回b
语法:
{ [P in K]?:T }
一些工具库,比如说Partial
,Required
,Pick
就是通过映射来实现的
比如现在有一个需求,需要把这个类型全部改为可选的,代码如下
type User = {name: string,password: string,address: string,phone: string,
}//里面的属性需要全部改为可选的
type User1 = {name?:string,password?:string,address?:string,phone?:string,
}
//你可以使用工具库当中的Partial,也可以自己写一个~
type selfPartial = {[K in keyof T]?:T[k]
}
+
,-
来添加.移除修饰符(+(加号为默认)) type Item =
{ a: string; b: number; c: boolean
};// { x: number,y: number }
type T1 = { [P in 'x' | 'y']: number };//{ x: 'x',y: 'y }
type T2 = { [P in 'x' | 'y']: P };//{a: string,b: number}
type T3 = { [P in 'a' | 'b']: Item[P] }//{a: string,b: number,c: boolean}
type T4 = { [P in keyof Item]: Item[P] }
ts的条件类型和js当中的三元运算符差不多
还是一句话,ts操作的是类型,js操作的是值
语法
T extends U ? X : Y
先来看一个简单的例子
type I2 = IsString
😕/输出类型为boolean,是因为any这二个值都可以满足,所以就为booleantype IsString = T extends string ? true :false;type I0 = IsString;// falsetype I1 = IsString<'abc'>;// true
type I2 = IsString;// boolean
type I3 = IsString;// never
type TypeName = T extends string ? string:T extends number ? number:T extends boolean ? boolean:T extends undefined ? undefined:T extends Function ? Function:Object;
type T0 = TypeName //string
type T1 = TypeName<'a'> //string
type T2 = TypeName //boolean
type T3 = TypeName<() => void> //Function
type T4 = TypeName //Object
type T5 = TypeName; //string | number | boolean | Function | Object//用js来书写上面的如下
function example(…) {return condition1 ? value1: condition2 ? value2: condition3 ? value3: value4;
}
// 等价于
function example(…) {if (condition1) { return value1; }else if (condition2) { return value2; }else if (condition3) { return value3; }else { return value4; }
}
type TypeName = T extends string ? string:T extends number ? number:T extends boolean ? boolean:T extends undefined ? undefined:T extends Function ? Function:Object;
type T10 = TypeName void)>;//string | Function
type T11 = TypeName//string | object | undefined
type Naked = T extends boolean ? "Y" : "N";
//分布式条件类型,判断每一个值是否都符合boolean
//是就为每一个值返回对应的结果
type T0 = Naked;// "Y" | "N"//判断传入的T当中的每一个值是否都符合boolean,是就只返回一个"Y",否则只返回一个"N"
type WrappedTuple = [T] extends [boolean] ? "Y" : "N";//判断传入的T当中的每一个值为boolean类型的数组
type WrappedArray = T[] extends boolean[] ? "Y" : "N";
type WrappedPromise = Promise extends Promise ? "Y" : "N";type T1 = WrappedTuple;// "N"
type T2 = WrappedArray;// "N"
type T3 = WrappedPromise;// "N;type T4 = WrappedTuple;// "Y";
type T5 = WrappedArray; //"Y"
Exclude
作用是传入T,U,将这两个相同的值消除,不同的值提取 type Exclude = T extends U ? never : T;//返回:c
type T4 = Exclude<'a' | 'b' | 'c','a' | 'b'>;//返回:never
type T5 = Exclude<'a' | 'b' ,'a' | 'b'>;
type T0 = string[];
type T1 = () => string;//需求,获取数组的类型和返回值的类型要怎么做?
//做法如下,
type UnpackedArray = T extends (infer U)[] ? U : T;
type T0Result = UnpackedArray; //string
infer
是什么呢?
T extends (infer U)[] ? U : T
:是条件类型的语法,而extends字句中的infer U 引入了一个新的类型变量U,用于存储被推断的类型,可以理解为后面这个U将用于存储类型infer
注意的点?
infer
只能在条件类型extends
字句中使用,同时infer
声明的类型变量只能在条件类型的true分支中可用type Wrong1 = T[0] // Error
type Wrong2 = (infer U)[] extends T ? U : T // Error
type Wrong3 = T extends (infer U)[] ? T : U // Error
那么infer
到底要怎么用呢?
infer
就长什么样子我们再来看看怎么判断函数的返回类型
//我们接着来下面这个的返回值类型
type T1 = () => string;
type T0 = string[];
type UnpackedFunction = T extends (...args:any[]) => (infer U) ? U : T;
//返回 string
type T1Types = UnpackedFunction//返回 string[]
type Test = UnpackedFunction
declare function foo(x:string):number;
declare function foo(x:number):string;
declare function foo(x:string | number):string | number;type UnpackedFn = T extends (...args:any[]) => (infer U) ? U : T ;//返回:string | number;
//代表返回类型
type U2 = UnpackedFn;
infer
,要判断的长什么样子,infer
就长什么样子(括号包起来)type Unpacked = T extends (...args:any[]) => (infer U) ? U : T extends (infer U)[] ? U :T extends Promise<(infer U)> ? U : T;
type T0 = Unpacked; // string
type T1 = Unpacked; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked>; // string
type T4 = Unpacked[]>; // Promise
type T5 = Unpacked[]>>; // string
type User = {id: number;name: string;
}type PropertyType = T extends {id: (infer U),name: (infer R) } ? [U,R] : T;
type U3 = PropertyType // [number, string]
type PropertyType = T extends { id: infer U, name: infer U } ? U : Ttype U4 = PropertyType // string | number
export interface tempType {a:(x:string) => void,b:(x:number) => void,
}
type Bar = T extends{a:(x:infer U) => void,b:(x:infer U) => void}? U : never;
// string 和 number 类型组合成的交叉类型
// 即最终的类型是 never 类型
type U5 = Bar; //string & number 为never
@部分转载CSDN织_网
type Partial = {[P in keyof T]?: T[P]
}
作用: Partial;把T当中的所有属性都变为可选
详细:生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为可选项
interface Foo {name: stringage: number
}
type Bar = Partial
// 相当于
type Bar = {name?: stringage?: number
}
type Required = {[K in keyof T]-?:T[K]
}
作用:Required:将T所有属性变为必填的
详细:生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为必选项
interface Foo {name: stringage?: number
}
type Bar = Required
// 相当于
type Bar = {name: stringage: number
}
type Pick = {[K in U]:T[K]
}
作用:Pick(A,B);从A当中挑选B并返回
详细:生成一个新类型,该类型拥有 T 中的 K 属性集 ;
新类型 相当于 T 与 K 的交集
interface Foo {name: string;age?: number;gender: string;
}
type Bar = Pick
// 相当于
type Bar = {age?: numbergender: string
}const todo: Bar= {age?: 3,gender: 男
};
type Exclude = T extends U ? never : T;
作用:Exclude; 排除A当中的B
详细: 如果 T 是 U 的子类型则返回 never 不是则返回 T(never可以理解为丢弃值不会返回)
type A = number | string | boolean
type B = number | booleantype Foo = Exclude
// 相当于
type Foo = string
type Extract = T extends U ? T : never;
作用:Extract 从A中提取B
详细: 如果 T 是 U 的子类型则返回 T 不是则返回 never (never可以理解为丢弃值不会返回)
type A = number | string | boolean
type B = number | booleantype Foo = Extract
// 相当于
type Foo = number | boolean
type Omit = Pick>
作用:Exclude; 排除A当中的B
详细: 如果 T 是 U 的子类型则返回 never 不是则返回 T(never可以理解为丢弃值不会返回)
type Foo = {name: stringage: number
}type Bar = Omit
// 相当于
type Bar = {name: string
}
type NonNullable = T extends null | undefined ? never : T;
作用:NonNullable;从T中排除null 和 undefined
详细: 从泛型 T 中排除掉 null 和 undefined
type t = NonNullable<'name' | undefined | null>;
//相当于
// type t = "name"
type Parameters any> = T extends (...args:infer P) => any ? P: never;
作用:Parameters< (形参) => 返回值 > 以元组的形式返回形参
详细: 以元组的方式获得函数的入参类型
type t = Parameters<(name: string) => any>; // type t = [string]type t2 = Parameters<((name: string) => any) | ((age: number) => any)>; // type t2 = [string] | [number]
export type ReturnType any> = T extends (...arg:any) => infer R ? R : any;
作用:ReturnType< (形参) => 返回值 >
详细: 获得函数返回值的类型
type t = ReturnType<(name: string) => string | number>
// type t = string | number
type Uppercase = intrinsic
Uppercase将StringType转为大写,TS以内置关键字intrinsic来通过编译期来实现。
type a = Uppercase<'abcDEF'>
//等同于
type a = 'ABCDEF';
type Lowercase = intrinsic;
Lowercase将StringType转为小写,TS以内置关键字intrinsic来通过编译期来实现。
type a = Lowercase<'abcDEF'>
//等同于
type a = 'abcdef';
type Capitalize = intrinsic;
Capitalize将StringType首字母转为大写。
type CapitalizeExample = Capitalize<"abc">;
//等同于
type CapitalizeExample = "Abc"
type Uncapitalize = intrinsic;
Uncapitalize将StringType首字母转为小写
type a = Uncapitalize<'AbcDEF'>
//等同于
type a = 'abcDEF';
上一篇:【Linux】多线程基础