本文讲解typescript语法
由于js语法本身的混乱,再加上目前框架的割据,导致typescript用起来没有一致性,本文尽量总结实际开发中可能会用到的知识点
目录
数据类型
类型断言
duck typing
函数类型的验证
索引验证
类验证
接口扩展
泛型
与第三方库一起使用
命名空间
react组件属性验证
-
Boolean 布尔类型 let isDone: boolean = false; Number 数字类型 let num: number = 5; String 字符串类型 let str: string = ‘aa‘; Array 数组 let list: number[] = [1, 2, 3]; let list: Array<nubmber> = [1, 2, 3]; let list: [string, number] = [‘aa‘, 11]; let arr: ReadonlyArray<number> = [1, 2, 3]; // 只读数组 Enum 枚举类型,是typescript对javascript语法的扩展类型 枚举类型用来将一组无意义的数值转变成识别度高的属性 enum Color {Red, Green, Blue} // 声明枚举 let a: Color = Color.Grean // 1 let a: string = Color[2]; // Blue 枚举值,默认从0开始递增,可以手动赋值 Any 类型,是typescript自己扩展的类型 any类型的作用就是用来暂时关闭类型验证,对此变量不做任何类型的验证,我不推荐用这个类型,建议Object代替 let a: any = 1; Object 类型,是typescript自己扩展的类型 Object类型的作用,是表示此变量可以为任意类型的值 let a: Object = 1; Void 类型,是typescript自己扩展的类型 Void 类型,主要用来表示没有返回值的函数 function a(): void {} Null 和 Undefined 类型 顾名思义,表示一个变量专门用来表示 Null 或者 Undefined let a: undefined = undefined; let a: null = null; Never 类型 用来表示报错的函数,或者死循环的函数 function fn() :never { throw new Error("aaa"); } function fn (): never { while(true) {} }
-
字面意思‘断言’,即人为决定类型,不需要typescript自动侦测 两种语法 尖括号语法,不推荐,此法react不支持 let str: Object = "aaa"; let strLength: number = (<string>someValue).length; as语法,推荐此语法,并且c#内部也推荐此语法 let str: Object = 111; let num: Number = str as Number;
-
duck typing是任何一门面相对象语言都有的类型验证方式,说简单点,就是一次验证多个变量 宽松的duck typing,只要变量需要验证的参数存在于传递的参数里面即可 对象写法 function fn(obj: {a: string}) {} let obj = {a: "aa", b: 1}; fn(obj); interface写法 interface params { a: string } function fn(obj: params) {} let obj = {a: "aa", b: 1}; fn(obj); 可选的参数 对象写法 function fn(obj: {a?: string}) {} interface写法 interface params { a?: string } function fn(obj: params) {} 只读的参数 对象写法 {readonly a: string} interface写法 interface params { readonly a: string } 严格的duck typing,传递的参数和验证的参数必须完全一致 interface params { a: string } function fn(obj: params) {} fn({a: "aa"}); 这种模式下可选参数已经失去了意义,为了挽救可选参数,解决方法有如下两种 as语法 interface params { a?: string, b?: number } function fn (obj: params): void {} fn({b: 11, c: "bb"} as params); 索引签名 interface params { a?: string, b?: number, [propName: string]: any } function fn (obj: params): void {} fn({b: 11, c: "bb", d: true});
-
函数的验证使用接口来实现会更加的简洁 interface myFn { (a: string, b: number): void } let fn: myFn = function(name, age){}; fn("aa", 11); 在定义函数时,函数的参数可以写类型也可以不写,并且参数的名称和接口的参数名称不需要相同 注意:在javascript中,函数其实就是一个对象,所以函数的验证可以存在即是对象又是函数的情况,如下 interface Test { (a: string): string; b: number; } function Fn() : Test { let fn = function(a: string){return a} as Test; fn.b = 111; return fn; } 函数验证的其他写法 let fn: (a: number) => void = function(x: number): void { } let fn = function(x: number): void { } let fn: (a: number) => void = function(x){ } let fn: (a?: number) => void = function(x){ } 可选参数 function fn(a: string | number){ } 多种参数类型
-
只要可以通过索引访问成员的数据类型,在typescript中都可以使用索引验证 众所周知,索引可以是字符串和数值,但是在js中,数值的索引等价于字符串的索引, 也就是说在typescript中,将索引指定为数值类型等价于字符串类型 interface Entries { [index: number]: number; } let arr: Entries = [1, 2, 3]; 同样还支持只读的索引 interface ReadonlyStringArray { readonly [index: number]: string; }
-
用接口验证类只能验证类的实例属性,构造函数这类的非实例属性无法验证 interface Test { a: string; fn(b: number): void; } class Demo extends React.Component implements Test { a: "aa" fn = (b: number) => { } } typescript对es6的类做了进一步的扩展,使其支持访问修饰符,抽象类抽象方法 访问修饰符 Public 默认,公开成员 private 只能在类内部访问 protected 本类内部和子类内部可以使用 Readonly 只读属性 static 静态属性 抽象类,作用和接口类似,主要用来给其他类提供公共成员 抽象类无法实例化,抽象方法只能提供定义,在子类中必须实现 abstract class Demo { a: string; fn():void { console.log("aa"); } constructor(a: string) {this.a = a}; abstract Fn(): void; } class Test extends Demo { constructor(){ super("aaaaaa"); } Fn():void { console.log("bbb"); } }
-
接口可以继承其他接口 interface Test1 { a: string; } interface Test2 { b: string; } interface Test3 extends Test1, Test2 { } 接口继承其他类 class Demo { public a: string; private b: number; protected c: string; } interface Test extends Demo {} class Demo1 extends Demo implements Test{ public a: "aa"; } 注意,由于接口继承类,接口可以继承类的private和protected成员,所以子类继承此接口要同时继承父类才行
-
泛型也是一个非常简单的东西,就是类型参数 泛型函数 function fn<T>(params: T): T { return params; } fn<string>(‘aa‘); 显示调用 fn(‘aa‘); 隐式调用 完整写法 let fn: <T>(params: T) => T = function<T>(params: T): T { return params; }; 泛型接口 不提取参数 interface Itf { <T>(params: T): T; } let fn: Itf = function<T>(params: T): T { return params; }; 提取参数 interface Itf<T> { <T>(params: T): T; } let fn: Itf<string> = function<T>(params: T): T { return params; }; 泛型类 class Demo<T>{ fn: (a: T) => T; } 泛型约束 没有泛型约束,泛型将毫无用处,泛型参数默认是个白板儿,啥都没有 一般写法 interface Demo { length: number; } function fn<T extends Demo>(str: T): T { window.console.log(str.length); return str; } fn(‘aa‘); 相互约束 function fn<T, K extends keyof T>(obj: T, key: K) { window.console.log(obj[key]); return obj[key]; } fn({a: 1}, ‘a‘); 验证类的构造函数 class Test { constructor(){} } function fn<T>(obj: {new(): T}): T{ return new obj(); } fn(Test);
-
很多基于npm的第三方包,都没有使用typescript,那么在ts中想使用这些安装包,需要遵从如下操作 第一,在项目中新建一个.d.ts文件,如 third.d.ts 第二,在文件中定义模块,如 declare module "url" { // 此模块名必须和第三方包的名字一样 export interface Url { protocol?: string; hostname?: string; pathname?: string; } export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url; } declare module "path" { export function normalize(p: string): string; export function join(...paths: any[]): string; export var sep: string; } declare module "hot-new-module"; 不想写声明可以不写 第三,在需要使用第三方包的文件中导入模块 /// <reference path="third.d.ts"/> 导入.d.ts声明文件 import * as URL from "url"; 导入模块 let myUrl = URL.parse("http://www.typescriptlang.org");
-
命名空间和js的对象一样,单纯的为了避免命名冲突 namespace Demo { export let a = ‘aa‘; } window.console.log(Demo.a);
-
使用React typings注入 interface Props { a: string; } class App extends React.Component<Props, {}> { render() { return ( <div className="App"> {this.props.a} </div> ); } } 使用此组件 <App a="aa"/>