阮一峰ts笔记

65 阅读4分钟
const s1: String = "123";
const s2: String = new String('asdas');
const s3: string = "123";
// const s4:string = new String('asdada');

const a: object = { foo: 'asd' }
// console.log(a.foo);


//交叉类型
let obj: { foo: string } & { bar: string }
obj = {
    foo: 'asd',
    bar: "asd"
}

//别名
type world = 'world'
type gree = `hello${world}`

//数组
let arr: number[] = [1, 2, 3]
let arr1: (string | number)[] = [1, '2']
let arr2: Array<string | number> = [1, '2']
// 只读数组 number[] 为 readonly number[]的子类型
let rarr: readonly number[] = [1, 2, 3]
let a1: ReadonlyArray<number> = [1, 2, 3]
let a2: Readonly<number[]> = [1, 2, 3]
//const 断言
const a3 = [1, 2, 3] as const
//二维数组
let arrd: number[][] = [[1, 2], [3, 4]]


//元祖
const t: [string, boolean?] = ['asd', true]
// 使用扩展运算符表示不限个数
const t1: [string, ...number[]] = ['asd', 1, 2, 3]
//只读元祖 只读元祖是元祖的父类型
type t = readonly [string, boolean?]
type t2 = Readonly<[string, boolean?]>


const t3: [...number[]] = [1, 2]
function tt(x: number, y: number) { }
tt(...t3 as [number, number])

//symbol unique symbol 是 symbol的子类型
const sy: unique symbol = Symbol()

//函数
const f1 = function name(params: string) { }
const f2: (text: string) => void = (text) => { }

function add(x: number, y: number) {
    return x + y
}
const myadd: typeof add = function (x, y) {
    return x + y
}

//函数以对象的形式声明
let foo: {
    (x: number): void;
    version: string;
} = f;
function f(x: number) {
    console.log(x);
}

f.version = "1.0";


type myfn = {
    (x: number): void
}
interface myfn2 {
    (x: number): void
}
//箭头函数
type Person = { name: string }
const peo = ['as'].map((name): Person => ({ name }))

//可选参数 不传时为undefined  
//但是如果是必选参数写明了类型 string|undefined 就必须传一个undefined2
let fnn = function (str?: string) {
    if (undefined !== str) { }
}
fnn()

//默认参数 str?:number=0 这样就会报错 
let funn = function (str: number = 0) { }
funn(undefined) //传入一个undefined 会触发默认值 str会等于0

//参数结构
function fnnn([x, y]: [number, number]) { }

//rse
function repeat(str: string, times: number): string { return 's' }
//等同于
function repeat2(...[str, tiems]: [string, number]): string { return 's' }
//只读参数
function repeat3(arr: readonly number[]) { }
//void 允许返回的值为null  strictNullChecks 改成false 也可以返回undefined 
function fu(): void {
    return undefined; // 正确
}
//   strictNullChecks false
//   function fn(): void {
//     return null; // 正确
//   }

type viodfunc = () => void
const fv: viodfunc = () => {
    return 123
}
// fv()*2 报错 声明时函数返回值是void 
//这种情况仅限于变量、对象方法和函数参数,函数字面量如果声明了返回值是 void 类型,还是不能有返回值。

// function fv2():void{
//     return 123
// }

//never 表示肯定不会出现的值
function fail(msg: string): never {
    throw new Error(msg)
}
// const sing = function (): never {
//     while (true) {
//       console.log("sing");
//     }
//   };

//never 表示函数没有执行结束 不会有返回值   
//void 表示正常执行结束 但是不返回值 或者值是undefined null

//高阶函数 返回一个箭头函数
(someVlue: number) => (multipliter: number) => someVlue * multipliter

//函数重载 
function reverse(str: string): string;
function reverse(arr: any[]): any[];
function reverse(strr: string | any[]): string | any[] {
    if (typeof strr === 'string') {
        return strr.split('').reverse().join('')
    } else {
        return strr.reverse()
    }
}

console.log(reverse("abc")); // 'cba'
console.log(reverse([1, 2, 3])); // [3, 2, 1]

// 重载签名不符
// function fc(x:boolean):void
// function fc(x:string):void
// function fc(x:string|number):void{}

//重载顺序 首先匹配到any 导致不会进行后面的匹配 会认定这个函数返回值是number 而不是 0|1
// function fcc(x: any): number
// function fcc(x: string): 0 | 1
// function fcc(x: string |any ): any { }
// const aaaaa: 0 | 1 = fcc('sadds')//报错

//对象方法重载
class pppp {
    add(str: string): this
    add(num: number): this
    add(value: any): any {
        return this
    }
}

// function createElement(tag: "a"): HTMLAnchorElement;
// function createElement(tag: "canvas"): HTMLCanvasElement;
// function createElement(tag: "table"): HTMLTableElement;
// function createElement(tag: string): HTMLElement {
//   // ...
// }
// 用对象表示函数重载
type CreateElement = {
    (tag: "a"): HTMLAnchorElement;
    (tag: "canvas"): HTMLCanvasElement;
    (tag: "table"): HTMLTableElement;
    (tag: string): HTMLElement;
};

// 写法一
function len1(s: string): number;
function len1(arr: any[]): number;
function len1(x: any): number {
    return x.length;
}

// 写法二 使用联合类型表示函数重载
function len2(x: any[] | string): number {
    return x.length;
}

//构造函数
class Animal {
    num: number = 4
}

type Animcons = new () => Animal

function create(c: Animcons): Animal {
    return new c()
}
const anmi = create(Animal)
// 对象写法 某些函数既是构造函数,又可以当作普通函数使用,比如Date()。这时,类型声明可以写成下面这样。
//F既可以当构造函数也可以当普通函数执行
type F = {
    new(s: string): object
    (n?: number): number
}



// 对象

const obj1: {
    x: number,
    y: number,
    add(x: number): number
} = {
    x: 1,
    y: 2,
    add(x: number) {
        return this.x + x
    }
}

type User = {
    name: string
}
type Name = User['name'] //string

type myface = {
    toString(): string // 从Object 继承的属性
    prop: number
}
const obj2: myface = {
    prop: 123
}

//  ?? 看左侧值是否的undefined或null时返回右侧的值 否则返回左侧的值
const user: {
    firstName: string;
    lastName?: string;
} = { firstName: "Foo" };
let firstName = user.firstName ?? "Foo";
let lastName = user.lastName ?? "Bar";

//只读
interface myinf {
    readonly prop: number
}

// const person1:{
//     readonly name:string
// }={name:'asd'}
// person1.name='asdas' //报错只读

const p2: {
    readonly aa: {
        name: string
    }
} = {
    aa: {
        name: 'sadasad'
    }
}
// p2.aa={}//报错aa是只读
p2.aa.name = 'asddaasdas'// 不报错 aa.name不是只读的


//可变对象赋值给只读对象 可变对象改变后也会影响只读对象 
interface Person1 {
    name: string;
    age: number;
}

interface ReadonlyPerson {
    readonly name: string;
    readonly age: number;
}

let w: Person1 = {
    name: "Vicky",
    age: 42,
};

let r: ReadonlyPerson = w;

w.age += 1;
r.age; // 43


const myuuser = {
    name: "asdad"
} as const
// myuuser.name='asdasd'//报错 只读断言
// myuuser.name='adsadadsa'

const myuuser2: { name: string } = {
    name: "asdad"
} as const
//明确声明了变量的类型以声明的类型为主
myuuser2.name = 'adsadadsa'

// 属性名的索引类型
type Myobj = {
    [p: string]: string
}
type T1 = {
    [property: number]: string;
};

type T2 = {
    [property: symbol]: string;
};
const obj3: Myobj = {
    name: 'asdasd',
    age: '123'
}
const arrrr: T1 = {
    1: 'asdasd',
    2: 'asdasd'
}
//报错 数值索引不能与字符串索引发生冲突,必须服从后者 
// type mmm={
//     [x:number]:boolean
//     [x:string]:string
// }

// 报错 ???? 符合属性名的字符串索引,但是两者的属性值类型不一样
// type mmmm={
//     num:number
//     [s:string]:string
// }
//

//不宜声明数组
// type MyArr = {
//     [n: number]: number;
//   };

//   const arr: MyArr = [1, 2, 3];
//   arr.length; // 报错

//结构赋值
// let{x:foo,y:bar}:{x:string,y:string} = obj

//B符合A的结构特征 所以可以成功赋值 说明B的属性可以多于A
const B = {
    x: 1,
    y: 1,
};

const A: { x: number } = B; // 正确

//如果一个对象属性多余myObj 就会导致obj传入的属性不止于xy
//使得v的值不值xy 还可能是其他 导致隐式的any类型
// type myObj = {
//     x: number;
//     y: number;
// };
// function getSum(obj: myObj) {
//     let sum = 0;

//     for (const n of Object.keys(obj)) {
//         const v = obj[n]; // 报错
//         sum += Math.abs(v);
//     }

//     return sum;
// }

// 字面量检查
//报错 等号右边是一个对象的字面量导致触发严格字面量检查
// const myPoint: {
//     x: number
// } = {
//     x: 1,
//     y: 2
// }

const myPoint = {
    x: 1,
    y: 2
}
const point: { x: number } = myPoint

let x: {
    foo: number;
    [x: string]: any;
};

x = { foo: 1, baz: 2 }; // Ok

//最小可选属性
// type Options = {
//     a?: number;
//     b?: number;
//     c?: number;
//   };

//   const obj: Options = {
//     a: 123, // 报错
//     d:12312312
//   } 

//空对象
const ddasd: {} = {}
//等同于 const d:object
let d1: {}
d1 = {}
d1 = { x: 1 }
//除了undefined或null都可以赋值


// interface
interface FOOOO {
    a: string
}
type Aaaaa = FOOOO["a"] //string

// 属性索引
interface AAAA {
    [prop: string]: number
}


interface AA {
    f(x: boolean): string
}
interface BB {
    f: (x: boolean) => string
}
interface CC {
    f: { (x: boolean): string }
}
const fffff = 'f'
interface DD {
    [fffff](x: boolean): string
}

// 重载
interface myinterface {
    f(): string
    f(x: string): number
    f(x: string, y: number): string
}

function myfunc(): string
function myfunc(x: string): number
function myfunc(x: string, y: number): string
function myfunc(x?: string, y?: number): string | number {
    if (x && y) {
        return x + y
    } else if (x) {
        return x
    } else {
        return 'asdasd'
    }
}


const aaaaa: myinterface = {
    f: myfunc
}

//声明函数
interface addd {
    (x: number, y: number): number
}
const myadddd: addd = (x, y) => x + y

// 声明构造函数
interface MyConstructor {
    new(x: number): number
}

// 继承
type count = {
    name: string
}
interface count1 extends count {
    age: number
}

// 继承类
class MyClass {
    name: string = ""
}
interface B extends MyClass {
    z: number
}
const bbb: B = {
    name: 'asdsad',
    z: 123
}

//同名合并
interface MyClass1123 {
    name: string
}
interface MyClass1123 {
    age: number
}

//优先级
//Animal最先声明等于排在最后面 优先级最低
// interface Cloner {
//     clone(animal: Animal): Animal;
// }

// interface Cloner {
//     clone(animal: Sheep): Sheep;
// }

// interface Cloner {
//     clone(animal: Dog): Dog;
//     clone(animal: Cat): Cat;
// }

// 等同于
// interface Cloner {
//     clone(animal: Dog): Dog;
//     clone(animal: Cat): Cat;
//     clone(animal: Sheep): Sheep;
//     clone(animal: Animal): Animal;
// }

// 字面量有更高的优先级
// interface A {
//     f(x: "foo"): boolean;
// }

// interface A {
//     f(x: any): void;
// }

// // 等同于
// interface A {
//     f(x: "foo"): boolean;
//     f(x: any): void;
// }


//this
interface fooo {
    add(num: number): this
}
// type foo={
//     add(num:number):this //报错
// }

//扩展原始数据
type mystr = string & {
    type: "new"
}
// interface mystr extends string{ //报错
//     type:"new"
// }


//存储器
class c {
    _name = ""
    get name(): string {
        return this._name
    }
    set name(value: number | string) {
        this._name = String(value)
    }
}

// 属性索引
class MyClass1 {
    [x: string]: boolean | ((s: string) => boolean)
    get(s: string) {
        return this[s] as boolean
    }
}

//检查条件
interface country {
    name: string
    age: number
}
class mycountry implements country {
    name = 'asd'
    age = 123
}
//implements 只能做检查但是不能代替声明
// interface country222 {
//     get(name:string):boolean

// }
// class mycountry222 implements country222 {
//     get(name){ // 报错 这里的name类型为any
//         return true
//     }
// }

//BBB没有声明可选属性y 可以通过检查 但是new后使用y就出了问题
// 需要在bbb中同样去声明y
// interface AAA{
//     x:number
//     y?:number
// }
// class BBB implements AAA{
//     x=123
// }
// const b = new BBB()
// b.y=123

//把其他类来当做检查 Car就会被当成一个检查接口
class Car {
    id: number = 1
}
class myCar implements Car {
    id: number = 1
}

//Car 实现MotorVehicle
// class Car implements MotorVehicle {}
//SecretCar继承Car 并且实现Flyable, Swimmable 等于 同时实现三个接口
// class SecretCar extends Car implements Flyable, Swimmable {}
//等同于
//接口继承
// interface MotorVehicle {
//     // ...
// }
// interface Flyable {
//     // ...
// }
// interface Swimmable {
//     // ...
// }

// interface SuperCar extends MotoVehicle, Flyable, Swimmable {
//     // ...
// }

// class SecretCar implements SuperCar {
//     // ...
// }
//接口里的属性不能冲突

//同名类接口合并
class A11 {
    x: number = 1;
}

interface A11 {
    y: number;
}

let a11 = new A11();
a11.y = 10;

a11.x; // 1
a11.y; // 10

class Point {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

// 错误 Point描述的是实例类型,而不是 Class 的自身类型。
//一个是实例 一个是实例的类型
function createPoint1(PointClass: typeof Point, x: number, y: number) {
    return new PointClass(x, y);
}
function createPoint2(PointClass: new (x: number, y: number) => Point, x: number, y: number) {
    return new PointClass(x, y);
}
function createPoint3(PointClass: {
    new(x: number, y: number): Point
}, x: number, y: number) {
    return new PointClass(x, y);
}

interface PointCons {
    new(x: number, y: number): Point
}

function createPoint4(PointClass: PointCons, x: number, y: number) {
    return new PointClass(x, y);
}

//静态属性和构造方法不同 但是实例成员相同就可以看做是兼容的
class point1 {
    x!: number;
    y!: number;
    static t: number
    constructor(x: number) { }
}
class posiiton {
    x!: number
    y!: number
    z!: number
    constructor(x: string) { }
}
const po: point1 = new posiiton("")

//有私有属性时 B需要继承A的私有属性才可以
class A111 {
    private name = 'a'
}
class B111 extends A111 { }
const a123: A111 = new B111()
//保护对象时也一样
class A1111 {
    protected name = 'asd'
}
class B1111 extends A1111 { }
const a123213: A1111 = new B1111()

class AA {
    greet() {
        console.log("Hello, world!");
    }
}
// 子类重写基类方法
class BB extends AA {
    greet(name?: string): void {
        if (name === undefined) {
            super.greet()
        } else {
            console.log(`hello ${name}`);

        }
    }
}
const b = new BB();
b.greet(); // "Hello, world!"

// 继承后可以把基类的属性改成公开的或保护的 改成私有的会报错
// class AAA {
//     protected x: string = "";
//     protected y: string = "";
//     protected z: string = "";
// }

// class BBB1 extends AAA {
//     // 正确
//     public x: string = "";

//     // 正确
//     protected y: string = "";

//     // 报错
//     private z: string = "";
// }


// class BB extends AA {
//     greet(name: string): void { //报错 与基类的方法定义冲突
//         console.log(`hello ${name}`);
//     }

// }

class AAA12 {
    greeting() {
        return 'sadsd'
    }
}
class BBB12 {
    greeting() {
        return 'sadsd'
    }
}


//extends 后面也可以是表达式 类型是构造函数就可以
interface Greeter {
    greeting(): string
}

interface getcon {
    new(): Greeter
}

function getbase(): getcon {
    return true ? AAA12 : BBB12
}

class Test extends getbase() {
    sayhello() {
        console.log('hello');

    }
}



// 细节
// interface Animal {
//     animalStuff: any;
// }

// interface Dog extends Animal {
//     dogStuff: any;
// }

// class AnimalHouse {
//     resident: Animal;

//     constructor(animal: Animal) {
//         this.resident = animal;
//     }
// }
// 报错  子类的那些只设置类型、没有设置初值的顶层成员在基类中被赋值后
// 会在子类被重置为undefined
// class DogHouse extends AnimalHouse {
//    resident: Dog;

//     constructor(dog: Dog) {
//         super(dog)

//     }
// }

// 修饰符
// class pri{
//     private x=1
// }
// const pria = new pri()
//私有化x 但是还能从通过这两种方法获取到
// pria['x']
// if("x" in a){}

// es6之后用#代替private
class pri {
    #x = 1
}
const pria = new pri()
// 这样就无法通过这种方式获取到私有属性
// pria['x']
// if ("x" in a)  {}

//单例模式 隐藏构造函数 只能调用静态方法创建实例 不能new
class singleton {
    private static instance?: singleton

    private constructor() { }

    static getInstaance() {
        if (!singleton.instance) {
            singleton.instance = new singleton()
        }
        return singleton.instance
    }
}

const ssssss = singleton.getInstaance()
console.log(ssssss);

//简写
class Point1 {
    x: number;
    y: number;

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}
// 自动做声明 public、private、protected、readonly
class Point2 {
    constructor(public x: number, public y: number) { }
}

//泛型类
class Box1<T> {
    contets: T
    // static id:T = 1  //报错 静态类型不能用泛型 
    constructor(value: T) {
        this.contets = value
    }
}

const box1: Box1<string> = new Box1<string>('asdsa')




// 抽象类,抽象成员 abstract
// 该类不能实例化  只能被当做模板 只能当基类使用 在此基础上定义子类
abstract class AA1 {
    id = 1
    // 未定义的抽象成员 需要子类添加该属性属性 否则报错
    // 抽象成员不能用修饰符 
    abstract foo: string;
}
// 一个子类最多继承一个抽象类
class BB1 extends AA1 {
    aut = 100
    foo = ';asd';
}
const bb1 = new BB1()
bb1.id
// 抽象类也可以继承抽象类
abstract class CC1 extends AA1 {
    name = 'asd'
}

//this 函数可以设置this的类型
// class aa1 {
//     name = "A"
//     getName(this: aa1) {
//         return this.name
//     }
// }
// const aa11 = new aa1()
// const bb11 = aa11.getName
// bb11() // 报错

//this可以声明为各种对象 可以要求this是带某个属性
function fooo(this: { name: string }) {
    this.name = 'ads'
    // this.name=123 //报错 与定义的this类型不符
}

// class A {
//     static a:this // 报错静态成员类型不能是this
//静态成员拿不到this实例对象
// }

//this is type 。。。。


//泛型
function map<T, U>(arr: T[], f: (age: T) => U): U[] {
    return arr.map(f)
}
map<string, number>(['1', '2', '3'], (n) => parseInt(n))


function id<T>(arg: T): T {
    return arg;
}
// 写法一
let myId1: <T>(arg: T) => T = id;

// 写法二
let myId2: { <T>(arg: T): T } = id;

//接口泛型写法
interface Box<T> {
    name: T
}
let box: Box<string> = {
    name: "asdsa"
}

//第二种
interface comp<T> {
    compar(value: T): number
}
class reac implements comp<reac>{
    compar(value: reac): number {
        return 1
    }
}
// ????
// interface fnnnn {
//     <Type>(age: Type): Type
// }
// function idd<Type>(age: Type): Type {
//     return age
// }
// let myid3: fnnnn = idd

//继承泛型
class A1<T> {
    name: T | undefined
}
class B1 extends A1<any>{ }

const contar = class <T>{
    constructor(private readonly data: T) { }
}
const contar1 = new contar<string>('asdsa')
const contar2 = new contar<number>(123)

class C<T>{
    value!: T
    add!: (x: T, y: T) => T
}
let fff = new C<number>()
fff.value = 0
fff.add = (x, y) => x + y

//用作构造函数上 泛型描述的的类的实例 不包括静态属性和方法
type myclass1<T> = new (...args: any[]) => T
interface myclass2<T> {
    new(...args: any[]): T
}

function create1<T>(anyclass: myclass1<T>, ...args: any[]): T {
    return new anyclass(...args)
}

//泛型的类型别名
type nullable<T> = T | undefined | null
//树形结构例子 递归引用
type tree<T> = {
    value: T
    left: tree<T> | null
    right: tree<T> | null
}

//默认值 有默认值就代表是可选参数 需要排在必选参数后面
function getfit<U, T = string>(arr: T[]): T {
    return arr[0]
}
//Array作为原生的一个类型接口 number作为泛型的类型参数
let arrr: Array<number> = [1, 2]
let arrr1: ReadonlyArray<number> = [1, 2] //只读数组

// 约束条件
//T 必须满足有数字类型的length否则就会报错
function comp<T extends { length: number }>(a: T, b: T) {
    return a.length === b.length
}
// comp(1,2) //没有length报错

//约束和默认值
type fnn1<A extends string, B extends string = 'world'> = [A, B]

type result = fnn1<'hello'>//['hello','world']

//多个类型参数 可以引用其他做约束
// <U,T extends U>
// <T,U extends T>
//但不可以作用自身
//<T extends T>//报错