常见的定义
const b: boolean = false;const n: number = 1;const s: string = 'abc';const n: null = null;const u: undefined = undefined;// 声明变量空值 只能复制undefined或者nullconst v: void = undefined || null;const union: string | number = 7;// 当访问联合类型的属性或方法时 只能访问共有属性和方法union.toString() // toString 共有readonly id:number; // 只读属性 只有在创建的时候可以赋值
空值返回函数
function func(): void {}
空值和undefined&null的区别是 void类型变量只能赋值undefined&null 但是声明为undefined&null的 可以和其他原始数据类型相互赋对应类型的值
任意值 any
const s; // s是任意值 不受类型约束const s = 7; // 推断为number 受number约束
接口声明
interface Person {name: string;age?: number; // 可选love: any; // 任意类型[propName: string]: string // 任意属性 如果用了任意属性 则其他成员属性必须是该任意属性类型的子类型// 此时任意属性类型是string, 所以name,age,love都应该为string或者undeined或者null[propName: string]: string | number | any // 这样就可以解决上面必须是它子类型的问题}
数组
const arr: number[] = [1, 2, 3] // 元素类型为number的数组const arr: Array<number> = [1, 2, 3]; // 泛型表示跟上面一条相等// 接口表示数组也可以interface NumberArray {[index: number]: number}// 类数组处理function sum() {let args: number[] = arguments; // 报错 arguments 不是数组}// 可以用接口表示 也可以用内置定义 IArguments 实现也相同function sum() {const args: {[index: number]: any;length: number;callee: Function;}}
函数表达式
函数是javascript的一等公民
// 函数声明function sum(x: number, y: number): number {return x + y;}// 函数表达式const mySum: (x: number, y: number) => number = function (x: number, y: number): number {return x + y;};// 用接口定义函数interface SearchFunc {(source: string, subString: string): boolean;}const mySearch: SearchFunc;mySearch = function(source: string, subString: string) {return source.search(subString) !== -1;}// 可选参数 可选参数后面不允许出现必须参数function func(name: string, age?: number)// 参数默认值function func(name: string = 'abc', age?: number)// es6的剩余参数 ...rest参数function push(array: any[], ...items: any[]) {array.push()...}push([], 1, 2, 3, 4)// 重载function reverse(x: number): number;function reverse(x: string): string;function reverse(x: number | string): number | string {if (typeof x === 'number') {return Number(x.toString().split('').reverse().join(''));} else if (typeof x === 'string') {return x.split('').reverse().join('');}}
类型断言(表达式)
欺骗typescript编译器 尽量避免 类型断言并不会实质修改变量类型 只是ts编译过程使用
// 语法值 as 类型 // animal as Cat 类型降级 动物降级成猫<类型>值 // <Cat>animal 类型降级 动物降级成猫// animal as Fishinterface Cat {name: string;run(): void;}interface Fish {name: string;swim(): void;}// 联合类型function isFish(animal: Cat | Fish) {if (typeof (animal as Fish).swim === 'function') {return true;}return false;}// 联合类型可以被断言为其中一个类型// 父类可以被断言为子类 继承// 任何类型都可以被断言为 any// any 可以被断言为任何类型// 若 A 兼容 B,那么 A 能够被断言为 B,B 也能被断言为 A 要使得 A 能够被断言为 B,只需要 A 兼容 B 或 B 兼容 A 即可// 要使得 A 能够被断言为 B,只需要 A 兼容 B 或 B 兼容 A 即可
双重断言
// 任何类型都可以被断言为 any// any 可以被断言为任何类型interface Cat {run(): void;}interface Fish {swim(): void;}function testCat(cat: Cat) {return (cat as any as Fish); // 牛逼}
声明文件
// 全局变量declare let jQuery: (selector: string) => any;declare var jQuery: (selector: string) => any;declare const jQuery: (selector: string) => any;// 全局方法declare function jQuery(selector: string): any;// 全局方法重载declare function jQuery(selector: string): any;declare function jQuery(domReadyCallback: () => any): any;// 全局类declare class Animal {name: string;constructor(name: string);sayHi(): string;}// 定义全局枚举declare enum Directions {Up,Down,Left,Right}// 定义全局变量对象declare namespace jQuery {function ajax(url: string, settings?: any): void;}declare namespace jQuery {function ajax(url: string, settings?: any): void;const version: number;class Event {blur(eventType: EventType): void}enum EventType {CustomClick}}// 命名空间嵌套declare namespace jQuery {function ajax(url: string, settings?: any): void;namespace fn {function extend(object: any): void;}}/ ************ /jQuery.ajax('/api/get_something');jQuery.fn.extend({check: function() {return this.each(function() {this.checked = true;});}});// 单属性空间嵌套declare namespace jQuery.fn {function extend(object: any): void;}/ ****** /jQuery.fn.extend({check: function() {return this.each(function() {this.checked = true;});}});// interface和type组合暴露两者// 声明interface AjaxSettings {method?: 'GET' | 'POST'data?: any;}declare namespace jQuery {function ajax(url: string, settings?: AjaxSettings): void;}// 使用let settings: AjaxSettings = {method: 'POST',data: {name: 'foo'}};jQuery.ajax('/api/post_something', settings);// 未避免命名冲突declare namespace jQuery {interface AjaxSettings {method?: 'GET' | 'POST'data?: any;}function ajax(url: string, settings?: AjaxSettings): void;}let settings: jQuery.AjaxSettings = {method: 'POST',data: {name: 'foo'}};jQuery.ajax('/api/post_something', settings);
类型别名
// 类型别名type Name = string;type NameResolver = () => string;type NameOrResolver = Name | NameResolver;function getName(n: NameOrResolver): Name {if (typeof n === 'string') {return n;} else {return n();}}
字符串字面量类型
// 限定了只能是这三类中的一类type EventNames = 'click' | 'scroll' | 'mousemove';function handleEvent(ele: Element, event: EventNames) {// do something}handleEvent(document.getElementById('hello'), 'scroll'); // 没问题handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'// index.ts(7,47): error TS2345: Argument of type '"dblclick"' is not assignable to parameter of type 'EventNames'.
枚举
enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; // 0,2,3,4,5,6...// 手动赋值 后续会在赋值后的值上累加enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu=99, Fri, Sat}; // Tue = 2, Fri = 100
extends
// TS的类型也支持条件运算,其语法与三目运算符相同,为T extends U ? X : Ytype IsEqualType<A, B> = A extends B ? (B extends A ? true : false) : false;type NumberEqualsToString = IsEqualType<number, string>; // falsetype NumberEqualsToNumber = IsEqualType<number, number>; // true// reduxexport type StateFromReducersMapObject<M> = M extends ReducersMapObject? { [P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never }: never
infer 待推断类型
// 如果T是继承 any的type ParamType<T> = T extends (param: infer P) => any ? P : T;type Unpacked<T> =T extends (infer U)[] ? U :T extends (...args: any[]) => infer U ? U :T extends Promise<infer U> ? U :T;// 1. T extends (infer U)[] = false, string 没有继承string[]// 2. T extends (...args: any[]) => infer U = false, string不是方法类型// 3. T extends Promise<infer U> = false, string不是Promise类型// 4. 返回Ttype T0 = Unpacked<string>; // stringtype T1 = Unpacked<string[]>; // string// 1. T extends (infer U)[] = false, string 没有继承string[]// 2. T extends (...args: any[]) => infer U = false, () => string 没有继承该方法类型// 3. T extends Promise<infer U> = false, string不是Promise类型// 4. 返回Ttype T2 = Unpacked<() => string>; // stringtype T3 = Unpacked<Promise<string>>; // string// 1. T extends (infer U)[] = true, T = Promise<string>, T extends Promise<string>[]// 2. 返回Ttype T4 = Unpacked<Promise<string>[]>; // Promise<string>type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
联合类型和extends条件推断
// 条件类型匹配 不是简单的三元运算type Other = "a" | "b";type Merge<T> = T extends "x" ? T : Other; // T 等于匹配的类型,然后加上 Other 联合类型一起返回type Values = Merge<"x" | "y">;// 得到 type Values = "x" | "a" | "b";type Other = "a" | "b";type Merge<T> = T extends "x" ? Other : T; // T 等于除匹配类型的额外所有类型(官方叫候选类型)type Values = Merge<"x" | "y">;// 得到 type Values = "a" | "b" | 'y';// 实际应用type MakesSense = never extends never ? 'yes' : 'no' // Resolves to 'yes'// never = 空联合类型 运行 ... extends never将无返回结果 所以 ExtendsNever<never> = nevertype ExtendsNever<T> = T extends never ? 'yes' : 'no'// [T] [never]已经切换比较的类型 所以 ExtendsNever<never> = 'yes'type ExtendsNever<T> = [T] extends [never] ? 'yes' : 'no'type MakesSenseToo = ExtendsNever<{}> // Resolves to 'no'type Huh = ExtendsNever<never> // is yes
新奇语法
// 相当于 user && user.userinfo && user.userinfo.usernameconst name: string = user?.userinfo?.username// user一定存在 userinfo一定存在 的语法表示const name: string = user!.userinfo!.username
infer关键字
export const tuple = <T extends string[]>(...args: T) => args;// eslint-disable-next-line import/prefer-default-exportexport const PresetColorTypes = tuple('pink','red','yellow',);// T extends xx T属于xx类型吗 判断语句 如果是 E是待推断类型 如果是E[]// 下面例子中T 是['pink', 'red', 'yellow'] 所以里面的元素类型为 'pink' | 'red' | 'yellow' 所以E='pink' | 'red' | 'yellow'export type ElementOf<T> = T extends (infer E)[] ? E : T extends readonly (infer F)[] ? F : never;// 'pink' | 'red' | 'yellow'export type PresetColorType = ElementOf<typeof PresetColorTypes>;
