内置类型

作者: shuaiutopia | 来源:发表于2020-06-29 13:52 被阅读0次

问题引出

我们需要渲染一个表格,往往需要定义:

interface Row {
  user: string
  email: string
  id: number
  vip: boolean
  // ...
}

const tableDatas: Row[] = []

有时候我们也需要表格对应的搜索表单,需要其中一两个搜索项,如果刚接触 typescript 的同学可能会立刻这样写:

interface SearchModel {
  user?: string
  id?: number 
}  
const model: SearchModel = {
  user: '',
  id: undefined 
}

这样写会出现一个问题,如果后面 id 类型要改成 string,我们需要改 2 处地方,不小心的话可能就会忘了改另外一处。所以,有些人会这样写:

interface SearchModel {
  user?: Row['user']
  id?: Row['id']
} 

这固然是一个解决方法,但事实上,我们前面已经定义了 Row 类型,这其实是可以更优雅地复用的:

// Partial 和 Pick 为内置类型
const model: Partial<Row> = {
  user: '',
  id: undefined 
}
// 或者需要明确指定 key 的,可以
const model2: Partial<Pick<Row, 'user'|'id'>>

上面使用到的 PartialPick 都是 typescript 内置的类型别名。

内置类型

Partial<T>

将类型 T 的所有属性标记为可选属性

type Partial<T> = {
    [P in keyof T]?: T[P];
};

使用场景:

// 账号属性
interface AccountInfo {
    name: string 
    email: string 
    age: number 
    vip: 0|1 // 1 是vip ,0 是非vip
}

// 当我们需要渲染一个账号表格时,我们需要定义
const accountList: AccountInfo[] = []

// 但当我们需要查询过滤账号信息,需要通过表单,
// 但明显我们可能并不一定需要用到所有属性进行搜索,此时可以定义
const model: Partial<AccountInfo> = {
  name: '',
  vip: undefind
}

Required<T>

Partial 相反,Required 将类型 T 的所有属性标记为必选属性

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

Readonly<T>

将所有属性标记为 readonly, 即不能修改

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

Pick<T, K>

从 T 中过滤出属性 K

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

使用场景:

interface AccountInfo {
  name: string 
  email: string 
  age: number 
  vip?: 0|1 // 1 是vip ,0 是非vip
}

type CoreInfo = Pick<AccountInfo, 'name' | 'email'>
/* 
{ 
  name: string
  email: string
}
*/

Record<K, T>

同时标记对象的 keyvalue 的类型

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

使用场景:

// 定义 学号(key)-账号信息(value) 的对象
const accountMap: Record<number, AccountInfo> = {
  10001: {
    name: 'xx',
    email: 'xxxxx',
    // ...
  }    
}
const user: Record<'name'|'email', string> = {
    name: '', 
    email: ''
}
// 复杂点的类型推断
function mapObject<K extends string | number, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>

const names = { foo: "hello", bar: "world", baz: "bye" };
// 此处推断 K, T 值为 string , U 为 number
const lengths = mapObject(names, s => s.length);  // { foo: number, bar: number, baz: number }

Exclude<T, U>,Omit<T, K>

移除 T 中的 U 属性

type Exclude<T, U> = T extends U ? never : T;

使用场景:

// 'a' | 'd'
type A = Exclude<'a'|'b'|'c'|'d' ,'b'|'c'|'e' >  

乍一看好像这个没啥卵用,但是,我们通过一番操作,之后就可以得到 Pick 的反操作:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

type NonCoreInfo = Omit<AccountInfo, 'name' | 'email'>
/*
{
  age: number 
  vip: 0|1,
}
*/

Extract<T, U>

Exclude 的反操作,取 T,U 两者的交集属性

type Extract<T, U> = T extends U ? T : never;

使用 demo:

// 'b'|'c'
type A = Extract<'a'|'b'|'c'|'d' ,'b'|'c'|'e' >  

这个看起来没啥用,实际上还真没啥卵用,应该是我才疏学浅,还没发掘到其用途。

NonNullable<T>

排除类型 Tnull | undefined 属性

type NonNullable<T> = T extends null | undefined ? never : T;

使用 demo

type A = string | number | undefined 
type B = NonNullable<A> // string | number

function f2<T extends string | undefined>(x: T, y: NonNullable<T>) {
    let s1: string = x;  // Error, x 可能为 undefined
    let s2: string = y;  // Ok
}

Parameters<T>

获取一个函数的所有参数类型

// 此处使用 infer P 将参数定为待推断类型
// T 符合函数特征时,返回参数类型,否则返回 never
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;

使用demo:

interface IFunc {
  (person: IPerson, count: number): boolean
}

type P = Parameters<IFunc> // [IPerson, number]

const person01: P[0] = {
  // ...
}

另一种使用场景是,快速获取未知函数的参数类型

import { somefun } from 'somelib'
// 从其他库导入的一个函数,获取其参数类型
type SomeFuncParams = Parameters<typeof somefun>

// 内置函数
// [any, number?, number?]
type FillParams = Parameters<typeof Array.prototype.fill>

ConstructorParameters<T>

类似于 Parameters<T>, ConstructorParameters 获取一个类的构造函数参数

type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;

使用 demo:

// string | number | Date 
type DateConstrParams = ConstructorParameters<typeof Date>

ReturnType<T>

获取函数类型 T 的返回类型

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

使用方式和 Parameters<T> 类似,不再赘述

InstanceType<T>

获取一个类的返回类型

type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;

使用方式和 ConstructorParameters<T> 类似,不再赘述

相关文章

  • 前端面试题(JS部分)

    内置类型 JS中分为七种内置类型,其中内置类型又分为两大类型: 基本类型 对象(Object) 基本类型有六种: ...

  • C++数据类型

    简介 C++数据类型包括基本内置类型、复合类型和自定义数据结构。 基本内置类型:编译器内置的基本类型,包括算数类型...

  • C++内存篇(一):内置类型的机器实现和sizeof

    内存篇(一):内置类型的机器实现和sizeof 一、内置类型的机器实现 C++内置类型及尺寸: 类型含义最小尺寸b...

  • Javascript 基础之类型

    内置类型 js 中内置类型一共 7 种(包括 es6),7 种内置类型可分为两大类型:基本类型 和 引用类型(对象...

  • 前端面试题(一)JS篇

    内置类型 JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。 基本类型有六种:...

  • JavaScript学习总结(1) —— 内置类型

    1. 内置类型 JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。基本类型有六...

  • 内置类型

    问题引出 我们需要渲染一个表格,往往需要定义: 有时候我们也需要表格对应的搜索表单,需要其中一两个搜索项,如果刚接...

  • 前端知识总结——js基础篇

    内置对象 JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。 基本类型有六种:...

  • Dart基础语法<二> 内置类型

    内置类型 ​对标Java 的八大内置基本数据类型,Dart 有以下七种内置类型: Numbers Strings...

  • golang内置类型和函数

    内置类型值类型: 引用类型:(指针类型) 内置函数Go 语言拥有一些不需要进行导入操作就可以使用的内置函数。它们有...

网友评论

    本文标题:内置类型

    本文链接:https://www.haomeiwen.com/subject/upuofktx.html