类型基本用法:
字符串 string
数字 number
数组 xxxtype[]
1
| let a: string[] = ["roc1", "roc2"];
|
null
undefined
1
| let a: undefined = undefined;
|
任意 any
1 2 3 4 5
| let a: any = "roc"; let b: any = 123; let c: string = b; console.log(c)
|
未知 unknown
1 2 3 4 5
| let a: unknown = "roc"; let b: unknown = 123; let c: string = b; console.log(c)
|
空 void
1 2 3 4 5 6
| function fn(): void { }
|
从未 never
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function fn(): never { while(true){} } function fn(arg: string | number) { switch (typeof arg) { case "string": console.log("string类型处理"); break; case "number": console.log("number类型处理"); break; default: const check: never = arg; } } fn("roc") fn(true)
|
元组 tuple [xxxtype]
1 2
| let a: [string, number, number] = ["roc", 18, 200]
|
函数参数&返回值类型
1 2 3 4 5 6 7 8 9 10
| function add(a: number, b: number): number { return a + b; }
const arr: string[] = ["roc1", "roc2", "roc3"]; arr.forEach((item) => { console.log(item); })
|
对象类型 {}
1
| const obj: {a: number, b: string} = {a: 123, b: "roc"}
|
可选类型 ?
1 2 3
|
const obj: {a: number, b: string, c?: number} = {a: 123, b: "roc", c: 200}
|
联合类型 |
1 2 3 4
| 用 "|" 可以有多个类型;但是内部一般需要进行类型判断处理 function fn(id: string | number | boolean) { console.log(id); }
|
类型别名 type
1 2 3 4 5 6 7 8 9 10 11 12
| 用"type"关键字定义类型 type myType = string | number | boolean; let my: myType = "roc";
type objType = { a: string, b: number } let obj: objType = { a: "roc", b: 18 }
|
类型断言 as
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
const el document.getElementById("roc") el.src = "";
const el document.getElementById("roc") as HTMLImageElement el.src = "";
不推荐使用 let a = "roc"; let b: number = a as any as number; let c: number = a as unknown as number;
|
非空类型断言 !
1 2 3 4 5 6 7 8 9 10 11
|
function printMsg(msg?: string) { console.log(msg.length); }
function printMsg(msg?: string) { console.log(msg!.length) }
|
可选链 ?.
它不是ts的语法特性,是ES11(ES2020)的语法特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| type infoType = { name: string, age?: number, friend?: { name: string, age?: number } }
const info: infoType = { name: "roc", friend: { name: "abc" } }
console.log(info.name)
console.log(info.friend?.name)
|
!!
本就是javascript语法
1 2 3 4
| let a = "hello"; let b = !!a
|
??
空值合并操作符是一个逻辑操作符;当左侧是null或者undefined时,返回右侧的操作数,否则返回左侧的操作数;与逻辑或 || 类似
1 2 3 4 5 6 7
| let a: string | null = "roc"; let b = a ?? "rocyuan"; console.log(b)
let a: string | null = null; let b = a ?? "rocyuan"; console.log(b)
|
字面量类型
1 2 3 4 5
| let a: "roc" = "roc"; let b: 123 = 123;
let c: "right" | "left" | "top" | "bottom" = "top"
|
函数详解
函数类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function add(a: number, b: number): number { return a + b; }
function fn1(fn: () => void) { fn() } function fn2() { console.log("我是fn2") } fn1(fn2)
type TypeFn = (a1: string) => string let fn: TypeFn = (a: string) => { return a; } console.log(fn("rocyuan"))
|
参数可选
结合可选类型
1 2 3
| function fn(a: string, b?: string){ }
|
参数的默认值
属于ES6的知识点
1 2 3 4 5 6 7 8 9 10
| function fn(a: number, b: number = 666){ console.log(a, b) } fn(20)
function fn(a: number = 666, b: number){ console.log(a, b) } fn(666, 20) fn(undefined, 20)
|
函数的剩余参数
1 2 3 4 5 6 7 8
| function add(...nums: number[]): number { let sum: number = 0; nums.forEach((item) => { sum += item }) return sum } add(1, 2, 3, 4);
|
函数的重载
1 2 3 4 5 6 7 8 9 10 11 12
| function add(a: number, b: number): number; function add(a: string, b: string): string;
function add(a: any, b: any): any { return a + b; }
let res1 = add(1, 2); let res2 = add("roc", "yuan"); console.log(res1, res2);
|
类 class
修饰符
public
在所有类都可访问
1 2 3
| class Roc{ public name: string = "rocyuan" }
|
private
只在当前类中能访问
1 2 3
| class Roc{ private name: string = "rocyuan" }
|
protected
在类中和子类中可访问
1 2 3
| class Roc{ protected name: string = "rocyuan" }
|
readonly
只读的 可以在构造器中赋值,赋值后不可修改
1 2 3
| class Roc{ readonly name: string = "rocyuan" }
|
访问器 get set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Roc{ private _name: string; constructor(name: string) { this._name = name; } set name(newName) { this._name = newName; } get name() { return this._name; } }
const roc: Roc = new Roc("roc");
roc.name = "rocyuan"; console.log(roc.name);
|
静态成员 static
可以通过类本身访问
1 2 3 4
| class Roc{ static name: string = "rocyaun" } console.log(Roc.name)
|
抽象类 abstract
抽象方法必须存在于抽象类里面,抽象类不能被实例化,抽象方法必须被子类实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
function makeArea(shape: Shape) { return shape.getArea() }
abstract class Shape { abstract getArea(); }
class Rectangle extends Shape { private width: number private height: number constructor(width: number, height: number) { super() this.width = width; this.height = height; } getArea() { return this.width * this.height; } }
class Circle extends Shape { private r: number constructor(r: number) { super() this.r = r; } getArea() { return this.r * this.r * 3.14; } }
console.log(makeArea(new Rectangle(3, 4))) console.log(makeArea(new Circle(3)))
|
继承 extends
继承只能单继承(继承一个类)
1 2
| class Roc extends RocYuan { }
|
接口 interface
接口声明
1 2 3 4 5 6 7 8 9
| interface IInfo { name: string age: number readonly height?: number } const info: IInfo = { name: "rocyuan", age: 18 }
|
索引类型
1 2 3 4 5 6 7 8
| interface IInfo { [index: number]: string } const info: IInfo = { 0: "字符串", 1: "字符串", 2: "字符串" }
|
函数类型
1 2 3 4 5 6 7
| interface IFn { (a: number): number }
const fn: IFn = (a: number) => { return a; }
|
接口继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| interface IFn1 { getName: () => string } interface IFn2 { getAge: () => number }
interface IFn3 extends IFn1, IFn2 { getHeight: () => number }
const roc: IFn3 = { getName(){ return "rocyuan" }, getAge() { return 18 }, getHeight() { return 188 } } console.log(roc.getName()) console.log(roc.getAge()) console.log(roc.getHeight())
|
接口实现
一个类是可以实现多个接口,用”,”分割;继承只能继承一个(单继承)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| interface IStudent1 { name: string age: number running: () => void } interface IStudent2 { height: number } class Student implements IStudent1, IStudent2 { name = "rocyuan" age = 18 height = 188 running() { console.log("跑") } }
const roc = new Student(); roc.running()
|
交叉类型(合并类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| interface IFn1 { getName: () => string } interface IFn2 { getAge: () => number } type TFn3 = IFn1 & IFn2
const fn: TFn3 = { getName() { return "rocyuan" }, getAge() { return 18 } } console.log(fn.getName()) console.log(fn.getAge())
|
interface与type的区别
interface 命名可以相同,如果名字一旦相同,则会合并定义的接口
type 是定义的别名,别名是不可以相同的
枚举enum
枚举类型默认的值是数字,比如我们经常用数字记录某些数据,判断数字处理逻辑,比如女,男,保密(0, 1, 2)…,使用枚举,可以大大增强代码可读性。
可简单理解为定义一常量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| enum ESex { GRIL, MALE, SEC } console.log(ESex.GRIL) console.log(ESex.MALE) console.log(ESex.SEC)
enum ESex { GRIL = 10, MALE, SEC }
|
泛型
认识泛型
泛型就是将类型参数化;调用者将类型以参数的形式赋值过来
泛型类型参数
1 2 3 4 5 6 7 8 9 10 11
| function roc<Type>(num: Type): Type { return num; }
roc<number>(666); roc<{name: "rocyuan"}>("rocyuan");
roc(50) roc("roc")
|
可接受多个参数
1 2 3 4 5 6 7
| function foo<T, E>(a1: T, a2: E) { return console.log(a1, a2); } foo<number, string>(666, "rocyuan")
foo(666, "rocyuan")
|
泛型接口
1 2 3 4 5 6 7 8 9 10
| interface IPerson<T1 = string, T2 = number> { name: T1 age: T2 }
const roc: IPerson<string, number> = { name: "rocyuan", age: 18 }
|
泛型类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Point<T> { x: T y: T z: T constructor(x: T, y: T, z: T) { this.x = x; this.y = y; this.z = z; } } const p1 = new Point<string>("12.12", "13.13", "14.14") const p2: Point<string> = new Point("12.12", "13.13", "14.14")
const p3 = new Point("12.12", "13.13", "14.14")
|
泛型的类型约束
对传入的泛型限制类型
1 2 3 4 5 6 7 8
| interface ILength { length: number } function getLength<T extends ILength>(arg: T) { return arg.length; } console.log(getLength("rocyuan"))
|
命名空间 namespace
最早期的时候叫内部模块,js没有模块化时候会使用,现在使用较少。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
export namespace roc1 { export function format() { return "2020-02-02" } } export namespace roc2 { export function format() { return "22.22" } } roc1.format() roc2.format()
import {roc1, roc2} from "xxx" roc1.format() roc2.format()
|
ts对类型的管理与查找规则(.d.ts文件,@types/xxx仓库)
文件后缀名为 .ts 是编写ts代码的最终会输出js代码文件。
文件后缀名为 .d.ts 是类型声明文件用来做类型检测的,它仅仅用来做类型检测,告知ts我们有哪些类型。
有的第三方库没有.d.ts声明文件引入后就会报错
内置类型声明
内置类型都是ts自带的
外部声明文件(第三方库类型声明)
- 下载第三方库时候第三方库里面有 .d.ts ;正常使用即可
- Ts社区维护的类型声明仓库:https://github.com/DefinitelyTyped/DefinitelyTyped,用npm安装:@types/xxx,比如react就有:@types/react;查询自己所使用的第三方库在这个仓库中有没有类型声明文件:https://www.typescriptlang.org/dt/search?search=,如果这里还没有那就得自己写了。
自定义声明文件
自己编写声明文件,新建xxx.d.ts,ts会自动识别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
declare module 'lodash' { export function join(arr: any[]): void }
declare let name: string declare function roc(): void
declare module '*.jpg' declare module '*.png'
declare namespace ${ export function ajax(settings: any): any }
import _ from "lodash"; import roc from "xxx/xx.jpg"; _.join(["aaa", "bbb"]) $.ajax({})
|