TS(四):TypeScript入门

tsconfig.json - compilerOptions

target

使用哪种js标准进行编译

  • 默认:ES3
  • 参数:es3 es5 es6/es2015 es2016 es2017 es2018 es2019 es2020 es2021 es2022 esnext

lib

库(数组配置): 当需要ts编译的脚本在浏览器上运行时,会有 document console 等浏览器的默认方法, 可以为他配置 ‘dom’ 参数。

参数 描述
ES5 所有 ES3 和 ES5 功能的核心定义
ES2015 ES2015(也称为 ES6)中可用的其他 API - array.find、Promise、Proxy、Symbol、Map、Set、Reflect等。
ES6 “ES2015”的别名
ES2016 ES2016 中可用的其他 API -array.include等。
ES7 “ES2016”的别名
ES2017 ES2017 中可用的其他 API - Object.entries, Object.values, Atomics, SharedArrayBuffer, date.formatToParts, 类型数组等。
ES2018 ES2018 中可用的其他 API -async可迭代、promise.finally、Intl.PluralRules、regexp.groups等。
ES2019 ES2019 中可用的其他 API - array.flat, array.flatMap, Object.fromEntries, string.trimStart,string.trimEnd等。
ES2020 ES2020 中可用的其他 API -string.matchAll等。
ES2021 ES2021 中可用的其他 API -promise.any等string.replaceAll。
ESNext ESNext 中可用的其他 API - 这会随着 JavaScript 规范的发展而变化
DOM DOM定义 - window,document等。
WebWorker WebWorker上下文中可用的 API
ScriptHost 适用于Windows 脚本托管系统的 API

modulemoduleResolution

module: 设置程序的模块系统(当程序进行模块化引用脚本时,把程序编译成哪种模式)

moduleResolution: 指定模块解析策略

  • compilerOptions.module = 'none'compilerOptions.moduleResolution = 'node'
/* 编译前 */
// modules/index.ts
export default {
    
    
    name: '张三',
    desc: '法外狂徒'
}

// app.ts
import who from './index';

class Person {
    
    
    name: string;
    age: number;

    constructor(name: string, age: number) {
    
    
        this.name = name;
        this.age = age;
    }

    getUserInfo() {
    
    
        console.log(`${
      
      this.name} - ${
      
      this.age}`);
    }

    sayWho() {
    
    
        console.log(`${
      
      who.name} - ${
      
      who.desc}`)
    }
}

const person = new Person('Person', 25);
person.getUserInfo();
person.sayWho();
/* 编译后 */
// modules/index.d.js
"use strict";
Object.defineProperty(exports, "__esModule", {
    
    value: true});
exports.default = {
    
    
    name: '张三',
    desc: '法外狂徒'
};

// app.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    
    
    return (mod && mod.__esModule) ? mod : {
    
    "default": mod};
};
Object.defineProperty(exports, "__esModule", {
    
    value: true});
const modules_1 = __importDefault(require("./index"));

class Person {
    
    
    name;
    age;

    constructor(name, age) {
    
    
        this.name = name;
        this.age = age;
    }

    getUserInfo() {
    
    
        console.log(`${
      
      this.name} - ${
      
      this.age}`);
    }

    sayWho() {
    
    
        console.log(`${
      
      modules_1.default.name} - ${
      
      modules_1.default.desc}`);
    }
}

const person = new Person('Person', 25);
person.getUserInfo();
person.sayWho();

sourceMap

为生成的JavaScript文件创建源映射文件(xxx.js.map)

resolveJsonModule

是否允许导入带有“.json”扩展名的模块(需要moduleCommonJS类型)

isolatedModules

确保每个文件都可以安全传输,而不依赖于其他导入

forceConsistentCasingInFileNames

区分大小写

strict

严格模式

esModuleInterop

提供两个helper函数__importStar__importDefault分别处理import * asimport default

skipLibCheck

跳过声明文件的类型检查(跳过类型为 .d.ts 的所有文件)。这可以在编译期间节省时间,但会牺牲类型系统的准确性

示例

{
    
    
  "compilerOptions": {
    
    
    "target": "esnext",
    "lib": [
      "esnext",
      "dom"
    ],
    "module": "CommonJS",
    "moduleResolution": "node",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

数据类型 及 部分操作

interface IData {
    
    
    str: string;        // 字符串
    num: number;        // 数字
    bool: boolean;      // 布尔
    n?: null;           // null
    un?: undefined;     // undefined

    arr: any[];         // 泛型数组
    list: Array<any>;   // 泛型数组

    obj1: object;       // 对象
    obj2: object;       // 对象

    func: Function;     // 函数

    data: any;          // 泛型

    str_num: string | number; // 字符串或数字

    un_know: unknown;
}

export class Data {
    
    
    _str: string;
    _num: number;
    _bool: boolean;
    _arr: any[];
    _list: Array<any>;
    _obj1: object;
    _obj2: object;
    _data: any;
    _func: Function;
    _str_num: string | number;
    _un_know: unknown;

    constructor({
    
    str, num, bool, arr, list, obj1, obj2, func, data, str_num, un_know}: IData) {
    
    
        this._str = str;

        this._num = num;

        this._bool = bool;

        this._arr = arr;
        this._list = list;

        this._obj1 = obj1;
        this._obj2 = obj2;

        this._func = func;

        this._data = data;

        this._str_num = typeof str_num === "string" ? str_num.toUpperCase() : str_num;

        this._un_know = un_know;
    }

    getData() {
    
    
        for (const key in this) {
    
    
            console.log(key, this[key]);
        }
    }
}

const data = new Data({
    
    
    str: '张三',
    num: 18,
    bool: true,
    arr: [],
    list: ['A', 123],
    obj1: {
    
    },
    obj2: [{
    
    name: 'Person'}],
    func: () => 123,
    data: {
    
    },
    str_num: '123abc',
    un_know: [123]
});

data.getData();

type interface 区别

type 不可重复定义, interface 可重复定义,重复定义类型合并 方式

type ZhanSan = {
    
    
    name: string;
    desc: string;
}
// 以下代码报错
// type ZhanSan = {
    
    
//     age: number;
// }

interface Person {
    
    
    name: string;
}

interface Person {
    
    
    age: number;
}

export class Person {
    
    
    constructor(zs: ZhanSan, lee: Person) {
    
    
        console.log(zs, lee)
    }
}

new Person({
    
    name: '张三', desc: '法外狂徒'}, {
    
    name: 'Person', age: 25});

扩展类型 方式

// type
type Animal = {
    
    
    name: string;
}

type Bear = Animal & {
    
    
    age: number;
}

const bear: Bear = {
    
    
    name: '熊',
    age: 1
}
// interface 
interface Animal {
    
    
    name: string;
}

interface Bear extends Animal {
    
    
    age: number;
}

const bear: Bear = {
    
    
    name: '熊',
    age: 1
}

类型断言(unknown 不知道什么类型)

export class Person {
    
    
    constructor(name: string) {
    
    
        console.log(name)
    }
}

let name: unknown;

new Person(name as string);
new Person(<string>name);

文字类型

export const getUserInfo = (name: string, status: 'left' | 'right' | 'center') => {
    
    
    console.log(`${
      
      name} - ${
      
      status}`);
}
getUserInfo('Person', 'left');

报错:Argument of type ‘string’ is not assignable to parameter of type ‘“right” | “left” | “center”’

解决方法如下:

const data = {
    
    
    name: 'Person',
    status: 'right'
} as const;
export const getUserInfo = (name: string, status: 'left' | 'right' | 'center') => {
    
    
    console.log(`${
      
      name} - ${
      
      status}`);
}
getUserInfo(data.name, data.status);
const data = {
    
    
    name: 'Person',
    status: 'right' as 'right'
};
export const getUserInfo = (name: string, status: 'left' | 'right' | 'center') => {
    
    
    console.log(`${
      
      name} - ${
      
      status}`);
}
getUserInfo(data.name, data.status);
const data = {
    
    
    name: 'Person',
    status: 'right'
};

export const getUserInfo = (name: string, status: 'left' | 'right' | 'center') => {
    
    
    console.log(`${
      
      name} - ${
      
      status}`);
}
getUserInfo(data.name, data.status as 'right');

枚举

// 编译前
export enum Direction {
    
    
    Up = 1,
    Right,
    Down,
    Left
}

console.log(Direction.Up)
// 编译后
"use strict";
Object.defineProperty(exports, "__esModule", {
    
    value: true});
exports.Direction = void 0;
var Direction;
(function (Direction) {
    
    
    Direction[Direction["Up"] = 1] = "Up";
    Direction[Direction["Right"] = 2] = "Right";
    Direction[Direction["Down"] = 3] = "Down";
    Direction[Direction["Left"] = 4] = "Left";
})(Direction = exports.Direction || (exports.Direction = {
    
    }));
console.log(Direction.Up);
//# sourceMappingURL=app.js.map

BigInt、Symbol

const a: bigint = BigInt(100);
const b: bigint = 100n;
console.log(a, b, a == b, a === b); // 100n 100n true true

const c: Symbol = Symbol('name');
const d: Symbol = Symbol('name');
console.log(c, d, c == d, c === d); // Symbol(name) Symbol(name) false false

in

type Person = {
    
    
    name: string;
}

interface Animal {
    
    
    name: string;
    age: number
}

interface Other {
    
    
    name?: string;
    func: () => void;
}

const funA = (xxx: Person | Animal) => {
    
    
    console.log('name', 'name' in xxx);
    console.log('age', 'age' in xxx);
}
funA({
    
    name: 'Person', age: 25}); // name true ; age true ;


const funB = (xxx: Person | Animal | Other) => {
    
    
    console.log('name', 'name' in xxx);
    console.log('age', 'age' in xxx);
    console.log('func', 'func' in xxx);
}
funB({
    
    name: 'Dog', age: 2, func: () => 'Person'}); // name true ; age true ; func true ;

instanceof

class Person {
    
    
    private _name: string;

    constructor(name: string) {
    
    
        this._name = name;
    }
}

const person: Person = new Person('Person');
console.log(person instanceof Person); // true

const obj: object = new Object({
    
    _name: 'Person'});
console.log(obj instanceof Person); // false

类型谓语

pet is Fish

type Fish = {
    
    
    swim: () => void
};

type Bird = {
    
    
    fly: () => void
}

// 判断传参是否为Fish类型
function isFish(pet: Fish | Bird): pet is Fish {
    
    
    console.log(!!(pet as Fish).swim);
    return !!(pet as Fish).swim;
}

isFish({
    
    
    swim: () => {
    
    
    }
}); // true
isFish({
    
    
    fly: () => {
    
    
    }
}); // false

never类型 (不存在状态)

const func = (data: string | number | boolean) => {
    
    
    switch (typeof data) {
    
    
        case 'string':
            return 'string';
        case 'number':
            return 'number';
        case 'boolean':
            return 'boolean';
        default:
            const _data: never = data;
            return _data;
    }
}
let data: any; // 定义一个泛型的变量
console.log(func(data as number));

调用签名

type Person = {
    
    
    fullName: string;
    (age: number): number;
    say: () => string;
}
const func = (person: Person) => {
    
    
    console.log(`${
      
      person.fullName} - ${
      
      person(25)} ; ${
      
      person.say()}`);
}

function person(age: number): number {
    
    
    return age;
}

person.fullName = 'Person';
person.say = (): string => `张三 - 18`;

func(person); // Person - 25 ; 张三 - 18

构造签名

interface Point {
    
    
    x: number;
    y: number;
    say: () => object;
}

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

class Point2D implements Point {
    
    
    x: number;
    y: number;

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

    say(): object {
    
    
        const data = {
    
    x: this.x, y: this.y};
        console.log(data);
        return data;
    }
}

const func = (pointConstructor: PointConstructor) => {
    
    
    new pointConstructor(1, 2).say();
}

func(Point2D);

限制泛型条件

function maxListCount<T extends {
      
       length: number }>(a: T, b: T): number {
    
    
    return a.length > b.length ? a.length : b.length;
}

console.log(maxListCount({
    
    length: 2}, [1, 2, 3, 4])); // 4

限制泛型返回值

// 以下代码报错
function maxListData<T extends {
      
       length: number }>(a: T, b: T): T {
    
    
    return a.length > b.length ? a : {
    
    length: 10}; // 报错: '{length: 10}' 不是定义的泛型T
}

// 以下代码正确
function maxListData<T extends {
      
       length: number }>(a: T, b: T): T {
    
    
    return a.length > b.length ? a : b;
}

console.log(maxListData({
    
    length: 10}, [1, 2, 3, 4])); // { length: 10 }
console.log(maxListData<string[] | number[]>(['1', '2'], [1, 2, 3, 4])); // [ 1, 2, 3, 4 ]

可选参数、默认参数

const funA = (name?: string) => console.log(name);

funA(); // undefined
funA('Person'); // Person

const funB = (name: string = 'Person') => console.log(name);

funB(); // Person
funB('Tom'); // Tom

索引签名

export {
    
    }

interface Person {
    
    
    [index: number]: string | number;

    [props: string]: string | number;

}

const person: Person = {
    
    
    0: 'PLee',
    name: 'Person',
    age: 25
}

console.log(person);
interface Person<T> {
    
    
    [index: number]: T;

    [props: string]: T;
}

const person: Person<string | number> = {
    
    
    0: 'PLee',
    name: 'Person',
    age: 25,
}

console.log(person)
class Person {
    
    
    [props: string]: number | ((s: string) => boolean);

    // error 不符合索引签名
    // name: string = 'Person';
    // ok
    age: number = 25;

    // ok
    fun() {
    
    
        return true
    }

    // error 不符合索引签名
    // fun(){
    
    
    //     return 1;
    // }

    // 构造函数不受影响
    constructor() {
    
    

    }
}

泛型类

class Person<T> {
    
    
    data: T;

    constructor(data: T) {
    
    
        this.data = data;
        console.log(this.data);
    }
}

new Person<string>('abc');

keyof

type Point = {
    
    
    x: number,
    y: number
}
type P = keyof Point;

// const p: P = 'abc'; // 报错 p只能是 'x' 或者 'y'
const p: P = Math.random() > 0.5 ? 'x' : 'y';

console.log(p);
function func<T, K extends keyof T>(obj: T, key: K) {
    
    
    console.log(obj[key])
}

// func({name: 'Person'}, 'abc'); // 报错 在泛型T中找不到abc,泛型K只能是'name'
func({
    
    name: 'Person'}, 'name');
func<object, never>({
    
    name: 'Person'}, <never>'name');

ReturnType、typeof

type Func = () => string[];
type Person = ReturnType<Func>;

const person: Person = ['Person']; // Func的返回类型是string[],那么定义的person的最终返回类型就应该是string[]
function funA(): string[] {
    
    
    return ['Person']
}

// 需求: 想要定义一个类型是funA的返回类型
// type Users = ReturnType<funA>; // 报错: funA不是一个类型,这里需要的是一个类型
type Users = ReturnType<typeof funA>;
const users: Users = ['Person'];

索引访问类型

type Person = {
    
    
    name: string,
    age: number
}

type Num = Person['age'];
type StrNum1 = Person['name' | 'age'];
type StrNum2 = Person[keyof Person];
const List = [
    {
    
    name: 'Person', age: 25},
    {
    
    name: '张三', desc: '法外狂徒'},
    {
    
    name: ['张三'], desc: '法外狂徒'},
]

type Name = typeof List[number]['name']; // 查找到的是 数组中每个元素下name的值类型
type Age = typeof List[number]['age'];
type Desc = typeof List[number]['desc'];


// const name1: Name = 1;  // error
const name2: Name = 'abc'; // ok
const name3: Name = ['1']; // ok

条件类型

interface Animal {
    
    
    name: string;
}

interface Dog extends Animal {
    
    
    woof(): void;
}

// Example1 最终返回为number
type Example1 = Dog extends Animal ? number : string;

// Example1 最终返回为string
type Example2 = RegExp extends Animal ? number : string;
  • 条件类型的应用
interface IdLabel {
    
    
    id: number;
}

interface NameLabel {
    
    
    name: string;
}

// 重载方式
function createLabel1(id: number): IdLabel;
function createLabel1(name: string): NameLabel;
function createLabel1(idOrName: number | string): IdLabel | NameLabel;
function createLabel1(idOrName: number | string): IdLabel | NameLabel {
    
    
    throw '';
}

// 条件类型判断方式
type IdOrName<T extends number | string> = T extends number ? IdLabel : NameLabel

function createLabel2<T extends number | string>(idOrName: T): IdOrName<T> {
    
    
    throw '';
}

条件类型约束

type MessageOf<T> = T extends {
    
     message: unknown } ? T['message'] : never;

type Email = {
    
    
    message: string;
}

// Example1 最终类型为string
type Example1 = MessageOf<Email>;
const str: Example1 = 'abc';

// Example1 最终类型为never
type Example2 = MessageOf<number>;
const ex2: Example2 = 'err' as never;

infer

在条件类型表达式中,可以在 extends 条件语句中使用 infer 关键字来声明一个待推断的类型变量。

type Flatten<T> = T extends infer U ? U : never;

const num: Flatten<string | number> = 123;
const str: Flatten<string | number> = 'abc';
type Flatten<T> = T extends Array<infer U> ? U : never;

const num1: Flatten<[string, number]> = 123;
const num2: Flatten<[number]> = 123;
const str1: Flatten<[string, number]> = 'abc';
const str2: Flatten<[string]> = 'abc';
const data: Flatten<string | number> = 'a' as never; // 推断不出来所以是never

分布式条件类型

type ToArray<T> = T extends any ? T[] : never;

// StrOrNumList 最终返回类型为 string[] | number[]
type StrOrNumList = ToArray<string | number>;

const list: StrOrNumList = Math.random() > 0.5 ? [1, 2, 3] : ['a', 'b', 'c'];
type ToArray<T> = [T] extends [any] ? T[] : never;

// StrOrNumList 最终返回类型为 (string | number)[]
type StrOrNumList = ToArray<string | number>;

const list: StrOrNumList = [1, 2, 'a', 'b'];

继承类的执行顺序

  • 1、基类的字段被初始化 Person
  • 2、基类的构造函数运行 Person
  • 3、派生类的字段被初始化 Person
  • 4、派生类的构造函数运行 Person
class Person {
    
    
    name: string;

    constructor(name: string) {
    
    
        this.name = name;
        console.log(this.name); // ProsperLee
    }
}

class Person extends Person {
    
    
    name: string = 'Person';

    constructor(name: string) {
    
    
        super(name);
        console.log(this.name) // Person
    }
}

const lee = new Person('ProsperLee');

console.log(lee); // Person { name: 'Person' }

// 'ProsperLee' ---> 'Person' ---> Person { name: 'Person' }

继承js中的内置类型

class MsgError extends Error {
    
    
    constructor(msg: string) {
    
    
        super(msg);

        // 解决低版本下找不到msgError.sayMsg方法运行报错问题,如在target为es5时
        Object.setPrototypeOf(this, MsgError.prototype);
    }

    sayMsg() {
    
    
        console.log(this.message);
    }
}

const msgError = new MsgError('ProsperLee');
msgError.sayMsg();

public、protected、private

public 公开的,任何对象内均可访问

protected 受保护的,类及子类能够访问

private 私有的,当前类内能够访问

const Person = class<T> {
    
    
    constructor(public a: T, protected b: T[], private c: number) {
    
    
        this.a = a;
        this.b = b;
        this.c = c;
    }
}

const person = new Person<string>('Person', ['a', 'b'], 10);
console.log(person.a);
// console.log(person.b); // Property 'b' is protected and only accessible within class 'Person ' and its subclasses.
// console.log(person.c); // Property 'c' is private and only accessible within class 'Person '.

类里的 static 区块 (#data仅供内部使用)

class Perosn {
    
    
    static #data = 'Person123';

    get data() {
    
    
        return Perosn.#data;
    }

    // 默认会执行
    static {
    
    
        Perosn.#data += '!@#';
    }

    static sayData() {
    
    
        console.log(Perosn.#data);
    }

    sayData() {
    
    
        console.log(Perosn.#data);
    }
}

// Property '#data' is not accessible outside class 'Perosn' because it has a private identifier.
// 属性“#data”在类“Perosn”之外不可访问,因为它有一个私有标识符。
// Perosn.#data = 'Person';

Perosn.sayData(); // Person123!@#

const person = new Perosn();
console.log(person.data); // Person123!@# (调用的get方法)
person.sayData(); // Person123!@# (调用的sayData方法)

泛型类

class Perosn<T> {
    
    
    _data: T;

    constructor(data: T) {
    
    
        this._data = data;
    }
}

const person = new Perosn<number>(123);
console.log(person._data); // 123

const person1 = new Perosn({
    
    name: 'Person'});
console.log(person1._data); // { name: 'Person' }

const person2 = new Perosn('Person');
console.log(person2._data); // Person

类中的this指向

class Person {
    
    
    data: string = 'Person';

    getData() {
    
    
        return this.data;
    }
}

const lee = new Person();

const tom = {
    
    
    data: 'Tom',
    getData: lee.getData
}

console.log(lee.getData()); // Person
console.log(tom.getData()); // Tom
class Person {
    
    
    data: string = 'Person';

    getData = () => {
    
    
        return this.data;
    }
}

const lee = new Person();

const tom = {
    
    
    data: 'Tom',
    getData: lee.getData
}

console.log(lee.getData()); // Person
console.log(tom.getData()); // Person

is

class Person<T> {
    
    
    value?: T;

    hasValue(): this is {
    
     value: T } {
    
    
        return !!this.value;
    }

    isClass<T extends Function>(target: T): this is T {
    
    
        return this instanceof target;
    }
}

class Person extends Person<any> {
    
    
}

const person: Person<any> = new Person();
const lee: Person = new Person();

console.log(person.isClass(Person));    // true
console.log(lee.isClass(Person));          // true
console.log(lee.isClass(Person));       // true

console.log(person.hasValue());         // false
person.value = 'Person';
console.log(person.hasValue());         // true

抽象类和成员

抽象类中可以没有抽象方法,但抽象方法一定在抽象类中

抽象类只能被继承,不能被实例化

派生类必须实现抽象类的抽象成员

abstract class Person<T> {
    
    

    constructor(public data: T) {
    
    
        this.data = data;
    }

    getData() {
    
    
        this.sayHello();
        return this.data;
    }

    abstract sayHello(): void;
}

class Person<T> extends Person<T> {
    
    
    sayHello() {
    
    
        console.log('Hello');
    }
}

const lee = new Person<object>({
    
    name: 'Person'});
console.log(lee.getData()); // Hello ---> { name: 'Person' }

ES模块

// 模块脚本

class Person {
    
    
    name: string = 'Person';
    age: number = 25;
}

export class Tom {
    
    
    name: string = 'Tom';
    age: number = 10;
}

export default Person;
// 入口脚本

// 1、引入方式 export default
// import Person from "./modules/Person";

// 2、引入方式 export
// import {Tom} from "./modules/Person";

// 3、引入方式 export 别名
// import {Tom as NewTom} from "./modules/Person";

// 4、引入方式 综合
import Person, {
    
    Tom, Tom as NewTom} from "./modules/Person";

// 4、引入方式 *
import * as Data from "./modules/Person";

console.log(Person, Tom, NewTom, Data.Tom, Data.default); // [class Person] [class Tom] [class Tom] [class Tom] [class Person]

CommonJS模块

$ npm i --save-dev @types/node

  • exports.属性
// 模块脚本

class Lee {
    
    
    name: string = 'Lee';
    age: number = 25;
}

class Tom {
    
    
    name: string = 'Tom';
    age: number = 10;
}

exports.data = {
    
    
    Lee,
    Tom
}

// 入口脚本

let person = require('./modules/Person');
console.log(person); // { data: { Lee: [class Lee], Tom: [class Tom] } }
  • module.exports
// 模块脚本

class Lee {
    
    
    name: string = 'Lee';
    age: number = 25;
}

class Tom {
    
    
    name: string = 'Tom';
    age: number = 10;
}

module.exports = {
    
    
    Lee,
    Tom
}

// 入口脚本

let person = require('./modules/Person');
console.log(person); // { Lee: [class Lee], Tom: [class Tom] }

猜你喜欢

转载自blog.csdn.net/weixin_43526371/article/details/124799243