[Résumé de 40 mots] Solidifiez votre fondation TypeScript ! (2) (Fin)

Continuez à créer, accélérez la croissance ! C'est le deuxième jour de ma participation au "Nuggets Daily New Plan · June Update Challenge",Cliquez pour voir les détails de l'événement

9. Protection des types

Identifiez automatiquement les attributs et les méthodes variables en identifiant le bloc de code exécuté par jugement

1. typeofProtection des types

function double(val: number | string) {
    if (typeof val === 'number') {
        val
    } else {
        val
    }
}
复制代码

2. instanceofProtection des types

class Cat { }
class Dog { }

const getInstance = (clazz: { new(): Cat | Dog }) => {
    return new clazz();
}
let r = getInstance(Cat);
if(r instanceof Cat){
    r
}else{
    r
}
复制代码

3. inProtection des types

interface Fish {
    swiming: string,
}
interface Bird {
    fly: string,
    leg: number
}
function getType(animal: Fish | Bird) {
    if ('swiming' in animal) {
        animal // Fish
    } else {
        animal // Bird
    }
}
复制代码

4. Types d'unions identifiables

interface WarningButton {
    class: 'warning'
}
interface DangerButton {
    class: 'danger'
}
function createButton(button: WarningButton | DangerButton) {
    if (button.class == 'warning') {
        button // WarningButton
    } else {
        button // DangerButton
    }
}
复制代码

Cinq.null protection

const addPrefix = (num?: number) => {
    num = num || 1.1;
    function prefix(fix: string) {
        return fix + num?.toFixed()
    }
    return prefix('zf');
}
console.log(addPrefix());
复制代码

Il convient de noter ici que ts ne peut pas détecter les types de variables de fonction interne

6. Protection de type personnalisée

interface Fish {
    swiming: string,
}
interface Bird {
    fly: string,
    leg: number
}
function isBird(animal: Fish | Bird):animal is Bird {
    return 'swiming' in animal
}
function getAniaml (animal:Fish | Bird){
    if(isBird(animal)){
        animal
    }else{
        animal
    }
}
复制代码

7. Protection de l'intégrité

interface ICircle {
    kind: 'circle',
    r: number
}
interface IRant {
    kind: 'rant',
    width: number,
    height: number
}
interface ISquare {
    kind: 'square',
    width: number
}
type Area = ICircle | IRant | ISquare
const isAssertion = (obj: never) => { }
const getArea = (obj: Area) => {
    switch (obj.kind) {
        case 'circle':
            return 3.14 * obj.r ** 2
        default:
            return isAssertion(obj); // 必须实现所有逻辑
    }
}
复制代码

10. Inférence de type

1. Inférence d'affectation

Déduit lors de l'affectation, le type s'écoule de droite à gauche et le type de variable sera déduit en fonction de l'affectation

let str = 'wj';
let age = 11;
let boolean = true;
复制代码

2. Inférence de valeur de retour

Déduire automatiquement le type de retour de la fonction

function sum(a: string, b: string) {
    return a + b;
}
sum('a','b');
复制代码

3. Inférence de fonction

Les fonctions sont déduites de gauche à droite

type Sum = (a: string, b: string) => string;
const sum: Sum = (a, b) => a + b;
复制代码

4. Inférence d'attribut

Le type de l'attribut peut être déduit de la valeur de l'attribut

let person = {
    name:'zf',
    age:11
}
let {name,age} = person;
复制代码

5. Inversion des types

Les types de variables peuvent être déduits à l'aide de typeofmots-clés

let person = {
    name:'zf',
    age:11
}
type Person = typeof person
复制代码

6. Opérateur d'accès à l'index

interface IPerson {
    name:string,
    age:number,
    job:{
        address:string
    }
}
type job = IPerson['job']
复制代码

7. Mappage des types

interface IPerson {
    name:string,
    age:number
}
type MapPerson = {[key in keyof IPerson]:IPerson[key]}
复制代码

11. Type croisé

Les types d'intersection sont une combinaison de plusieurs types en un seul type

interface Person1 {
    handsome: string,
}
interface Person2 {
    high: string,
}
type P1P2 = Person1 & Person2;
let p: P1P2 = { handsome: '帅', high: '高' }
复制代码

Exemple : Nous fournissons deux groupes de personnes, un groupe est beau et l'autre groupe est grand. On veut trouver leur intersection => grand et beau mec

  • type croix
function mixin<T, K>(a: T, b: K): T & K {
    return { ...a, ...b }
}
const x = mixin({ name: 'zf' }, { age: 11 })
复制代码
interface IPerson1 {
    name:string,
    age:number
}

interface IPerson2 {
    name:number
    age:number
}
type person = IPerson1 & IPerson2
let name!:never
let person:person = {name,age:11};  // 两个属性之间 string & number的值为never
复制代码

12. Types de conditions

1. Utilisation de base des types conditionnels

Vous pouvez utiliser des extendsmots clés et des expressions ternaires pour obtenir un jugement conditionnel

interface Fish {
    name1: string
}
interface Water {
    name2: string
}
interface Bird {
    name3: string
}
interface Sky {
    name4: string
}
type Condition<T> = T extends Fish ? Water : Sky;
let con1: Condition<Fish> = { name2: '水' }
复制代码

2. Répartition des types de conditions

let con2: Condition<Fish|Bird> = { name2: '水' } 
复制代码

Ici, chaque élément est distribué à son tour, et finalement le type d'union est utilisé comme résultat, ce qui équivaut à :

type c1 = Condition<Fish>;
type c2 = Condition<Bird>;
type c = c1 | c2
复制代码

3. Type de condition intégré

  • 1. ExcludeTypes d'exclusions
type Exclude<T, U> = T extends U ? never : T;
type MyExclude = Exclude<'1' | '2' | '3', '1' | '2'>
复制代码
  • 2. ExtractType d'extraction
type Extract<T, U> = T extends U ? T : never;
type MyExtract = Extract<'1' | '2' | '3', '1' | '2'>
复制代码
  • 3. NoNullable Détection non vide
type NonNullable<T> = T extends null | undefined ? never : T
type MyNone = NonNullable<'a' | null | undefined>
复制代码

4. déduire l'inférence de type

  • 1. ReturnTypeType de valeur de retour
function getUser(a: number, b: number) {
  return { name: 'zf', age: 10 }
}
type ReturnType<T> = T extends (...args: any) => infer R ? R : never
type MyReturn = ReturnType<typeof getUser>
复制代码
  • 2. Parameters Type de paramètre
type Parameters<T> = T extends (...args: infer R) => any ? R : any;
type MyParams = Parameters<typeof getUser>;
复制代码
  • 3. ConstructorParametersTypes de paramètres constructeur
class Person {
  constructor(name: string, age: number) { }
}
type ConstructorParameters<T> = T extends { new(...args: infer R): any } ? R : never
type MyConstructor = ConstructorParameters<typeof Person>
复制代码
  • 4. InstanceType Type d'instance
type InstanceType<T> = T extends { new(...args: any): infer R } ? R : any
type MyInstance = InstanceType<typeof Person>
复制代码

Five.infer pratique

Convertir le type tableau en type union

type ElementOf<T> = T extends Array<infer E> ? E : never;
type TupleToUnion = ElementOf<[string, number, boolean]>;
复制代码

Convertir les arguments de deux fonctions en types croisés

type T1 = { name: string };
type T2 = { age: number };
type ToIntersection<T> = T extends ([(x: infer U) => any, (x: infer U) => any]) ? U : never;
type t3 = ToIntersection<[(x:T1)=>any,(x:T2)=>any]>
复制代码

表示要把T1T2赋予给x,那么x的值就是T1T2的交集。(参数是逆变的可以传父类)

TS的类型:TS主要是为了代码的安全性来考虑。所以所有的兼容性问题都要从安全性来考虑!

13.内置类型

一.Partial转化可选属性

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
// type Partial<T> = { [K in keyof T]?: T[K] }; 实现原理
type PartialPerson = Partial<Person>;
复制代码

遍历所有的属性将属性设置为可选属性,但是无法实现深度转化!

type DeepPartial<T> = {
    [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}
type DeepPartialPerson = DeepPartial<Person>;
复制代码

我们可以实现深度转化,如果值是对象继续深度转化。

二.Required转化必填属性

interface Company {
    num: number
}
interface Person {
    name: string,
    age: string,
    company: Company
}
type PartialPerson = Partial<Person>;
type Required<T> = {[K in keyof T]-?:T[K]} 
type RequiredPerson = Required<PartialPerson>
复制代码

将所有的属性转化成必填属性

三.Readonly转化仅读属性

type Readonly<T> = { readonly [K in keyof T]: T[K] }
type RequiredPerson = Readonly<Person>
复制代码

将所有属性变为仅读状态

四.Pick挑选所需的属性

type Pick<T, U extends keyof T> = { [P in U]: T[P] }
type PickPerson = Pick<Person, 'name' | 'age'>
复制代码

在已有类型中挑选所需属性

五.Record记录类型

type Record<K extends keyof any, T> = { [P in K]  : T }
let person: Record<string, any> = { name: 'zf', age: 11 };
复制代码

实现map方法,我们经常用record类型表示映射类型

function map<T extends keyof any, K, U>(obj: Record<T, K>, callback: (item: K, key: T) => U) {
    let result = {} as Record<T, U>
    for (let key in obj) {
        result[key] = callback(obj[key], key)
    }
    return result
}
const r = map({ name: 'zf', age: 11 }, (item, key) => {
    return item
});
复制代码

六.Omit忽略属性

let person = {
    name: 'wj',
    age: 11,
    address: '回龙观'
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type OmitAddress = Omit<typeof person, 'address'>
复制代码

忽略person中的address属性 (先排除掉不需要的key,在通过key选出需要的属性)

14.装包和拆包

一.装包

type Proxy<T> = {
    get():T,
    set(value:T):void
}
type Proxify<T> = {
    [P in keyof T]: Proxy<T[P]>
} 
let props = {
    name: 'wj',
    age: 11
}
function proxify<T>(obj:T):Proxify<T>{
    let result = {} as Proxify<T>;
    for(let key in obj){
        let value = obj[key];
        result[key] = {
            get(){
                return value
            },
            set:(newValue)=>value = newValue
        }
    }
    return result
}
let proxpProps = proxify(props);
复制代码

二.拆包

function unProxify<T>(proxpProps:Proxify<T>):T{
    let result = {} as T;
    for(let key in proxpProps){
        let value = proxpProps[key];
        result[key] = value.get()
    }
    return result
}
let proxy = unProxify(proxpProps)

复制代码

15.自定义类型

一.Diff实现

求两个对象不同的部分

let person1 = {
    name: 'wj',
    age: 11,
    address: '回龙观'
}
let person2 = {
    address: '回龙观',
}
type Diff<T extends object,K extends Object> = Omit<T,keyof K>
type DiffPerson = Diff<typeof person1,typeof person2>
复制代码

二.InterSection交集

let person1 = {
    name: 'wj',
    age: 11,
    address: '回龙观'
}
let person2 = {
    address: '回龙观',
}
type InterSection<T extends object, K extends object> = Pick<T, Extract<keyof T, keyof K>>
type InterSectionPerson = InterSection<typeof person1, typeof person2>
复制代码

三.Overwrite属性覆盖

type OldProps = { name: string, age: number, visible: boolean };
type NewProps = { age: string, other: string };

type Diff<T extends object,K extends Object> = Omit<T,keyof K>
type InterSection<T extends object, K extends object> = Pick<T, Extract<keyof T, keyof K>>
type Overwrite<T extends object, K extends object, I = Diff<T,K> & InterSection<K,T>> = Pick<I,keyof I>
type ReplaceProps = Overwrite<OldProps, NewProps>
复制代码

如果存在已有属性则使用新属性类型进行覆盖操作

四.Merge对象合并

type Compute<A extends any> = { [K in keyof A]: A[K] };
type Merge<T, K> = Compute<Omit<T, keyof K> & K>;
type MergeObj = Merge<OldProps,NewProps>
复制代码

将两个对象类型进行合并操作

16.unknown

一.unknown类型

unknown类型,任何类型都可以赋值为unknown类型。 它是 any 类型对应的安全类型

let unknown:unknown;
unknown = 'zf';
unknown = 11;
复制代码

不能访问unknown类型上的属性,不能作为函数、类来使用

  • 联合类型中的unknown

    type UnionUnknown = unknown | null | string | number
    复制代码

    联合类型与unknown都是unknown类型

  • 交叉类型中的unknown

    type inter = unknown & null
    复制代码

    交叉类型与unknown都是其他类型

二.unknown特性

  • never是unknown的子类型

    type isNever = never extends unknown ? true : false;=
    复制代码
  • keyof unknown 是never

    type key = keyof unknown;
    复制代码
  • unknown类型不能被遍历

    type IMap<T> = {
        [P in keyof T]:number
    }
    type t = IMap<unknown>;
    复制代码

unknown类型不能和number类型进行 +运算,可以用于等或不等操作

17.模块和命名空间

默认情况下 ,我们编写的代码处于全局命名空间中

一.模块

文件模块: 如果在你的 TypeScript 文件的根级别位置含有 import 或者 export,那么它会在这个文件中创建一个本地的作用域 。

// a.ts导出
export default 'zf'

// index.ts导入
import name from './a'
复制代码

二.命名空间

命名空间可以用于组织代码,避免文件内命名冲突

  • 命名空间的使用

    export namespace zoo {
        export class Dog { eat() { console.log('zoo dog'); } }
    }
    export namespace home {
        export class Dog { eat() { console.log('home dog'); } }
    }
    
    let dog_of_zoo = new zoo.Dog();
    dog_of_zoo.eat();
    let dog_of_home = new home.Dog();
    dog_of_home.eat();
    复制代码
  • 命名空间嵌套使用

    export namespace zoo {
        export class Dog { eat() { console.log('zoo dog'); } }
        export namespace bear{
            export const name = '熊'
        } 
    }
    console.log(zoo.bear.name); 
    复制代码

命名空间中导出的变量可以通过命名空间使用。

18.类型声明

一.声明全局变量

  • 普通类型声明
declare let age: number;
declare function sum(a: string, b: string): void;
declare class Animal { };
declare const enum Seaons{
    Spring,
    Summer,
    Autumn,
    Winter
}
declare interface Person {
    name:string,
    age:number
}
复制代码

类型声明在编译的时候都会被删除,不会影响真正的代码。目的是不重构原有的js代码,而且可以得到很好的TS支持

练习: 声明jQuery类型

jquery通过外部CDN方式引入,想在代码中直接使用

declare const $:(selector:string)=>{
    height(num?:number):void
    width(num?:number):void
};
$('').height();
复制代码
  • 命名空间声明
declare namespace jQuery {
    function ajax(url:string,otpions:object):void;
    namespace fn {
        function extend(obj:object):void
    }
}
jQuery.ajax('/',{});
jQuery.fn.extend({});
复制代码

namespace表示一个全局变量包含很多子属性 , 命名空间内部不需要使用 declare 声明属性或方法

二. 类型声明文件

类型声明文件以.d.ts结尾。默认在项目编译时会查找所有以.d.ts结尾的文件

// jquery.d.ts
declare const $:(selector:string)=>{
    height(num?:number):void
    width(num?:number):void
};

declare namespace jQuery {
    function ajax(url:string,otpions:object):void;
    namespace fn {
        function extend(obj:object):void
    }
}
复制代码

三.编写第三方声明文件

配置tsconfig.json

  • jquery声明文件
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
    "*": ["types/*"]
},
复制代码
// types/jquery/index.d.ts

declare function jQuery(selector: string): HTMLElement;
declare namespace jQuery {
    function ajax(url: string): void
}
export = jQuery;
复制代码
  • events模块声明文件
import { EventEmitter } from "zf-events";
var e = new EventEmitter();
e.on('message', function (text) {
   console.log(text)
})
e.emit('message', 'hello');
复制代码
export type Listener = (...args: any[]) => void;
export type Type = string | symbol

export class EventEmitter {
   static defaultMaxListeners: number;
   emit(type: Type, ...args: any[]): boolean;
   addListener(type: Type, listener: Listener): this;
   on(type: Type, listener: Listener): this;
   once(type: Type, listener: Listener): this;
}
复制代码

四.模块导入导出

import $ from 'jquery'  // 只适用于 export default $

const $ = require('jquery'); // 没有声明文件可以直接使用 require语法

import * as $ from 'jquery'  // 为了支持 Commonjs规范 和 AMD规范 导出时采用export = jquery

import $ = require('jquery')  // export = jquery 在commonjs规范中使用
复制代码

五.第三方声明文件

@types是一个约定的前缀,所有的第三方声明的类型库都会带有这样的前缀

npm install @types/jquery -S
复制代码

当使用jquery时默认会查找 node_modules/@types/jquery/index.d.ts 文件

查找规范

  • node_modules/jquery/package.json 中的types字段
  • node_modules/jquery/index.d.ts
  • node_modules/@types/jquery/index.d.ts

19.扩展全局变量类型

一.扩展局部变量

可以直接使用接口对已有类型进行扩展

interface String {
    double():string
}
String.prototype.double = function () {
    return this as string + this;
}
let str = 'wj';
复制代码
interface Window {
    mynane:string
}
console.log(window.mynane)
复制代码

二.模块内全局扩展

declare global{
    interface String {
        double():string;
    }
    interface Window{
        myname:string
    }
}
复制代码

声明全局表示对全局进行扩展

三.声明合并

同一名称的两个独立声明会被合并成一个单一声明,合并后的声明拥有原先两个声明的特性。

1.同名接口合并

interface Animal {
    name:string
}
interface Animal {
    age:number
}
let a:Animal = {name:'zf',age:10};
复制代码

2.命名空间的合并

  • 扩展类

    class Form {}
    namespace Form {
        export const type = 'form'
    }
    复制代码
  • 扩展方法

    function getName(){}
    namespace getName {
        export const type = 'form'
    }
    复制代码
  • 扩展枚举类型

    enum Seasons {
        Spring = 'Spring',
        Summer = 'Summer'
    }
    namespace Seasons{
        export let Autum = 'Autum';
        export let Winter = 'Winter'
    }
    复制代码

3.交叉类型合并

import { createStore, Store } from 'redux';
type StoreWithExt = Store & {
    ext:string
}
let store:StoreWithExt
复制代码

四.生成声明文件

配置tsconfig.json 为true 生成声明文件

"declaration": true
复制代码

完结撒花

Ce qui précède est toutes les TypeScriptbases . Les maîtriser est plus que suffisant pour l'entretien, mais il faut encore plus de pratique pour la langue. Bienvenue à aimer et favori!

Je suppose que tu aimes

Origine juejin.im/post/7102996554541170696
conseillé
Classement