Typescript 基础介绍

TS 是什么?

TypeScript is JavaScript with syntax for types.

TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.

TS 为了解决什么问题?

The goal of TypeScript is to be a static typechecker for JavaScript programs - in other words, a tool that runs before your code runs (static) and ensures that the types of the program are correct (typechecked).

TS基本类型

string、number、boolean、bigInt、null、undefined、void

Array、Tuple

ini 复制代码
const arr = ['hello', 18, false]
type typeArr = typeof arr
type numberArr = typeArr[number]  //  string | number | boolean

const tuple = ['hello', 18, false] as const
type typeTuple = typeof tuple
type numberTuple = typeTuple[number]  // false | "hello" | 18

Funciton、(...args: any) => any

typescript 复制代码
// 声明了一个function
function greeterFn(name: string): void {
  console.log(`hello, ${name}`);
}

// 给function加描述
greeterFn.desc = 'greeter desc'

// Call Signatures
type Greeter = {
  desc: string
  (name: string): void
}

function callGreeter(fn: Greeter) {
  console.log(fn.desc + " :" + fn('call'));
}

// 重载
function greeter(age: number): void
function greeter(name: string): string
function greeter(age: number, name: string): string
function greeter(age: string | number, name?: string) {
  if (typeof age === 'number') {
    console.log('my age is 18!')
    return
  }
  if (!name) {
    name = age
  }
  return name
}

const g1 = greeter(18) // void
const g2 = greeter('枫荷') // string
const g3 = greeter(18, '枫荷') // string
const g4 = greeter('18', '枫荷') // error // Argument of type 'string' is not assignable to parameter of type 'number'.

// 协变、逆变 下期细说

Class、 new (...args: any) => any constructor

Object 、object 、record<string, any>

ini 复制代码
// 区别
// Object Contains stuff (like toString(), hasOwnProperty()) that is present in all JavaScript objects.
// Any value (primitive, non-primitive) can be assigned to Object type
type O = Object;
let O1: O = 1; // 正确
let O2: O = ''; // 正确
let O3: O = {}; // 正确
let O4: O = { name: '枫荷' }; // 正确
//  It is any non-primitive type. 
// You can't assign to it any primitive type like bool, number, string, symbol.
type o = object;
let o1: o = 1;  // ts提示报错
let o2: o = ''; // ts提示报错
let o3: o = {};  // 正确
let o4: o = { name: '枫荷' }; // 正确
o4.name  // ts 报错 Property 'name' does not exist on type 'object'

type R = Record<string, any>
let r1: R = 1;  // ts提示报错
let r2: R = ''; // ts提示报错
let r3: R = {}; // 正确
let r4: R = { name: '枫荷' };  // 正确
r4.name. // 正确

Any

python 复制代码
type intersectionAny = 1 & any  // any
type unionAny = 1 | any  // any

Unkown

The unknown type represents any value. This is similar to the any type, but is safer because it's not legal to do anything with an unknown value:

typescript 复制代码
type intersectionUnknown = 1 & unknown  // 1
type unionUnknown = 1 | unknown  // Unknown

never

typescript 复制代码
type intersectionNever = 1 & never  // never
type unionNever = 1 | never  // 1

联合类型

typescript 复制代码
type id = number | string

类型声明

Type Alias (类型别名)

interface

An interface declaration is another way to name an object type:

  1. 区别

the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable

Type 能做类型推导

interface只能声明object type

typescript 复制代码
// extend
interface IAnimal {
  name: string
}

interface IBear extends IAnimal {
  honey: boolean
}

type TAnimal = {
  name: string
}

type TBear = TAnimal & { 
  honey: boolean 
}

// reopen
interface IWindow {
  title: string
}

interface IWindow {
  toString: Function
}

type TWindow = {
  title: string
}

type TWindow = { // Error: Duplicate identifier 'TWindow'.
  toString: FunctionAPI
}

// 类型推导
type isAny<T> = 1 extends 0 & T ? true : false

// 别名
type ID = string | number

类型断言

TypeScript only allows type assertions which convert to a more specific or less specific version of a type.

typescript 复制代码
const myCanvas = <HTMLCanvasElement>document.getElementById("myCanvas");

myCanvas.getContext("2d")?.fillRect(0, 0, 100, 100)

const myCanvas2 = document.getElementById("myCanvas") as HTMLCanvasElement;

const string = "Hello World" as unknown as number;

泛型

A major part of software engineering is building components that not only have well-defined and consistent APIs, but are also reusable. Components that are capable of working on the data of today as well as the data of tomorrow will give you the most flexible capabilities for building up large software systems.

类型操作(基础)

属性描述

typescript 复制代码
type Person = {
    name: string; // required
    age?: number; // optional
    readonly sex: string // readonly
}
// 去optional -?
// 去readonly -readonly

Keyof

typescript 复制代码
type Person = {
  name: string; // required
  age?: number; // optional
  readonly sex: string; // readonly
};
type keys = keyof Person;  // name | age | sex

Typeof

ini 复制代码
const Person = {
  name: '枫荷',
  age: 18,
  sex: '男',
};
type IPerson = typeof Person;
/**
 * type IPerson = {
    name: string;
    age: number;
    sex: string;
  }
 */

Index

ini 复制代码
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];

简单操作

scala 复制代码
type Partial<T> = {
  [P in keyof T]?: T[P]
}

type Required<T> = {
  [P in keyof T]-?: T[P]
}

type Record<K extends keyof any, V> = {
  [P in K]: V
}

type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

type Exclude<T, K> = T extends K ? never : T

type Readonly<T> = {
  readonly [P in keyof T]: T[P]
}

type RemoveReadonly<T> = {
  -readonly [P in keyof T]: T[P]
}

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never

type Awaited<T extends PromiseLike<any>> = T extends PromiseLike<infer R> ? R extends PromiseLike<any> ? Awaited<R> : R : T

conditional

Extends

  1. 声明、等式左边(表示继承)

    scala 复制代码
      class Animal {
          name: string
      }
    
      class Dog extends Animal {
          bark: () => void
      }
    
      function toString <T>(arg: T) {
          if (typeof arg === 'string') {
              return arg
          }
          return `${arg}`
      }
    
      function toStringWithLimit<T extends string | number>(arg: T) {
        if (typeof arg === 'string') {
          return arg
        }
        return `${arg}`
      }
    
      type NumberToString<T extends number> = `${T}`
      ```
    
    1.  ######   ts中继承一般分为两种形式
    
    1.  小的集合继承自大的集合
    
      1.  ```
          type oneExtendsNumber = 1 extends number ? true : false // true
          ```
    
    1.  方法多的继承自方法少的(object)
    
      1.  ```
          class Animal {
              name: string
          }
    
          class Dog extends Animal {
              bark: () => void
          }
    
          let animal: Animal // name
          let dog: Dog // name、bark
    
          type arrayExtendsReadonlyArr = [] extends readonly [] ? true : false // true
          ```
  2. 等式右边(表示条件判断)

    java 复制代码
    T extends U ? X : Y
    1. ts中的extends运算规则

    2. 参数:分发

      1. T' 代表T中的每一项, U' 代表你需要判断T' 是否继承自 U'的任意值
      scala 复制代码
      type Union = 1 | 2
      
      type StringUnion1<T extends string | number> = T extends any ? `${T}` : never // 1 | 2
      type StringUnion2<T extends string | number> = T extends T ? `${T}` : never // 1 | 2
      type StringUnion3<T extends string | number> = T extends 1 ? `${T}` : never // 1 | never => 1
    3. 结果:协变 => 并集(covariant => union),逆变 => 交集(contravariant => intersection)

      typescript 复制代码
      // 协变
      type union = 1 | 2
      type StringUnion = union extends any ? `${union}1` : never
      
      // 逆变
      type unionFn = ((name: string) => string) | ((age: number) => number)
      type FnUnion1 = unionFn extends (args: infer P) => infer R ? [P, R] : never

Infer (Type inference in conditional types)

Within the extends clause of a conditional type, it is now possible to have infer declarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multiple infer locations for the same type variable.

typescript 复制代码
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

type Unpacked<T> = T extends (infer U)[]
  ? U
  : T extends (...args: any[]) => infer U
  ? U
  : T extends Promise<infer U>
  ? U
  : T;
type T0 = Unpacked<string>; // string
type T1 = Unpacked<string[]>; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked<Promise<string>>; // string
type T4 = Unpacked<Promise<string>[]>; // Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string

// 函数重载类型
declare function foo(x: string): number;
declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
// 这里推导是返回最后一次声明的结果
type T30 = ReturnType<typeof foo>; // string | number

协变和逆变

  1. 子集(SubType)

    typescript 复制代码
       class Animal {
         name: string;
    
         constructor(name: string) {
           this.name = name;
         }
       }
    
       class Dog extends Animal {
         bark() {
           console.log('wang wang !')
         }
    
         constructor(name: string) {
           super(name);
         }
       }
    
       // Dog is SubType of Animal
       // Dog <: Animal
    
       type IsSubtypeOf<S, P> = S extends P ? true : false;
    
       type T11 = IsSubtypeOf<Dog, Animal>; // true
       type T12 = IsSubtypeOf<'hello', string>; // true
       type T13 = IsSubtypeOf<42, number>; // true
       type T14 = IsSubtypeOf<Map<string, string>, Object>; // true
       ```
       
  2. 协变 (Covariance)

如果一个操作是协变的,那么则有以下规则 > > A <: B > > Co<: Co1 ``` type T21 = IsSubtypeOf<Promise, Promise> // true

[**````ini
type RecordOfDog = Record<string, Dog>;
type RecordOfAniAnimal = Record<string,Animal>;
type T22 = IsSubtypeOf<RecordOfDog, RecordOfAniAnimal>; // true
type MapOfDog = Map<string, Dog>;
type MapOfAniAnimal = Map<string,Animal>;
type T23 = IsSubtypeOf<MapOfDog, MapOfAniAnimal>; // true

复制代码
  1. 逆变 (Contravariance)](https://link.juejin.cn?target= "")> [如果一个操作是逆变的,那么则有以下规则

A <: B](https://link.juejin.cn?target= "")
Con**<: Con**

**[```typescript
type Func = (param: Param) => void;
type T31 = IsSubtypeOf<Func, Func> // false
type T32 = IsSubtypeOf<Func, Func> // true
type FuncAnimal = (p: Animal) => void;
type FuncDog = (p: Dog) => void;
type T33 = IsSubtypeOf<Dog, Animal>; // true
type T34 = IsSubtypeOf<FuncAnimal, FuncDog>; // true

复制代码
4. Ts 中的函数
> Ts 中函数的参数是逆变的,返回值是协变的
```ini
type FuncAnimal1 = (p: Animal) => '1' | '2';
type FuncDog1 = (p: Dog) => string;
type T41 = IsSubtypeOf<FuncAnimal1, FuncDog1> // true
type T42 = IsSubtypeOf<FuncDog1, FuncAnimal1> // false
type FuncAnimal2 = (p: Animal) => string;
type FuncDog2 = (p: Dog) => '1' | '2';;
type T43 = IsSubtypeOf<FuncAnimal2, FuncDog2> // false
type T44 = IsSubtypeOf<FuncDog2, FuncAnimal2> // false

最后的例子

typescript 复制代码
import { ReactNode } from 'react';
type IApiResponse = {
items?: IItems[];
totalCount?: number;
pageIndex?: number;
pageSize?: number;
totalPages?: number;
indexFrom?: number;
hasPreviousPage?: boolean;
hasNextPage?: boolean;
/** 采购数量合计 */
totalPurchaseQuantity?: number;
/** 采购金额合计 */
totalPurchaseAmount?: number;
/** 其他应付合计 */
totalOtherShouldPay?: number;
/** 其他应付合计 */
totalOtherShouldReceive?: number;
};
type IItems = {
/** 单据状态名称 */
statusName?: string;
/** 采购单Id */
id?: string;
/** 采购单编码 */
purchaseOrderCode?: string;
/** 订单需求编号 */
orderDemandCode?: string;
/** 订单类型Id */
orderTypeId?: string;
};
type GetApiValue<T> = T extends (...args: any) => PromiseLike<infer R> ? R : never;
type GetApiRows<T> = GetApiValue<T> extends { items?: infer R }
? R extends any[]
? R[number] & { feDataIndex: number }
: any
: any;
interface ITableSummaryItem<T> {
dataIndex: keyof T;
// 对应total的key,如果不传则默认为小记,如果传了则显示对应的key
totalKey?: string;
render?: (value: T[]) => ReactNode;
}
const api = () => Promise.resolve({} as IApiResponse)
type IProps<T=any> = {
api: T
onClick: (row: GetApiRows<T>) => void
onSelect: (rows: Array<GetApiRows<T>>) => void
summary?: ((summaryData: T) => ReactNode) | Array<ITableSummaryItem<GetApiRows<T>>>;
}
function Test<T extends (...args: any) => Promise<any> = (...args: any) => Promise<any>>(props: IProps<T>) {
return (
<div>
<h1>Test</h1>
</div>
)
}
function App() {
// records:any ?
const render = (records: GetApiRows<typeof api>[]) => {
records.map((item) => {
item.orderTypeId
})
return <>1</>
}
return (
<div className="App">
<Test
api={api}
onSelect={(rows) => {
rows.map((row) => {
row.orderTypeId
row.orderDemandCode
})
}}
onClick={(row) => {
row.orderDemandCode
}}
summary={[
{
dataIndex: 'orderDemandCode',
totalKey: 'orderDemandCodeTotal',
render,
}
]}
/>
</div>
)
}
export default App
```](https://link.juejin.cn?target= "")****
相关推荐
To_OC4 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel6 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_8 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx8 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师8 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow8 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路9 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他9 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou1329 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙9 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript