TypeScript 学习笔记(六):索引签名类型、映射类型

这篇具有很好参考价值的文章主要介绍了TypeScript 学习笔记(六):索引签名类型、映射类型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、索引签名类型

1. 索引类型查询操作符 keyof

keyof可以用于获取某种类型的所有键,其返回类型是联合类型。

keyofObject.keys 略有相似,只不过 keyofinterface 的键

interface Info {
  name: string;
  age: number;
}
let infoProp: keyof Info;
infoProp = "name";
infoProp = "age";
infoProp = "no"; // error 不能将类型“"no"”分配给类型“"name" | "age"”
 

通过例子可以看到,这里的keyof Info其实相当于"name" | “age”。通过和泛型结合使用,TS 就可以检查使用了动态属性名的代码:

// 这里使用泛型,并且约束泛型变量K的类型是"keyof T",也就是类型T的所有字段名组成的联合类型
function getValue<T, K extends keyof T>(obj: T, names: K[]): T[K][] { 
// 指定getValue的返回值类型为T[K][],即类型为T的值的属性值组成的数组
  return names.map(n => obj[n]); 
}
const info = {
  name: "lison",
  age: 18
};
let values: string[] = getValue(info, ["name"]);
values = getValue(info, ["age"]); // error 不能将类型“number[]”分配给类型“string[]” 
  • 接口
interface Person {
  name: string;
  age: number;
  location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // number | "length" | "push" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string | number

  • 基本数据类型
let K1: keyof boolean; // let K1: "valueOf"
let K2: keyof number; // let K2: "toString" | "toFixed" | "toExponential" | ...
let K3: keyof symbol; // let K1: "valueOf"

class Person {
    name: string = 'lisi';
}

let sname = keyof Person
sname = 'name'

如果把sname = ‘name’改为sname = ‘yui’的话,TypeScript 编译器会提示以下错误信息:

Type '"yui"' is not assignable to type '"name"'.

报错原因:

keyof Person 获取到的类型是‘name’

来看个简单的例子:

  let a: 1;
  a = 1;
  a = 2;

上的例子,将a的类型为1,那么这个变量的值只能是1,不能为其他的,当a = 2执行的时候,就会报错
TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端

  • 案例
function prop(obj: object, key: string) {
  return obj[key];
}

在上面代码中,为了避免调用 prop 函数时传入错误的参数类型,我们为 obj 和 key 参数设置了类型,分别为{}string 类型。然而,针对上述的代码,TypeScript 编译器会输出以下错误信息:

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端
解决方法:

function prop<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

在以上代码中,我们使用了 TypeScript 的泛型泛型约束首先定义了T类型并使用extends关键字约束该类型必须是object类型的子类型,然后使用keyof操作符获取 T 类型的所有键,其返回类型是联合类型,最后利用extends关键字约束 K 类型必须为keyof T联合类型的子类型。

type Todo = {
  id: number;
  text: string;
  done: boolean;
}

const todo: Todo = {
  id: 1,
  text: "Learn TypeScript keyof",
  done: false
}

function prop<T extends object, K extends keyof T>(obj: T, key: K) {
  return obj[key];
}

const id = prop(todo, "id"); // const id: number
const text = prop(todo, "text"); // const text: string
const done = prop(todo, "done"); // const done: boolean
const date = prop(todo, "date"); // 会报错

变量 date 访问todo对象中不存在的属性,那么就会报错
TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端

a. typeof与keyof的结合

const COLORS = {
  red: 'red',
  blue: 'blue'
}

// 首先通过typeof操作符获取color变量的类型,然后通过keyof操作符获取该类型的所有键,
// 即字符串字面量联合类型 'red' | 'blue',取自于k
type Colors = keyof typeof COLORS 
let color: Colors;
color = 'red' // Ok
color = 'blue' // Ok

// Type '"yellow"' is not assignable to type '"red" | "blue"'.
color = 'yellow' // Error

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端

b. T[K] 索引访问

  interface Eg1 {
    name: string,
    readonly age: number,
  }
  // string
  type V1 = Eg1['name']
  // string | number
  type V2 = Eg1['name' | 'age']
  // any 类型“Eg1”上不存在属性“age2222”
  type V3 = Eg1['name' | 'age2222']
  // string | number
  type V4 = Eg1[keyof Eg1]

结论:

T[keyof T]的方式,可以获取到T所有key的类型组成的联合类型;

T[keyof T]的方式,获取到的是T中的key且同时存在于K时的类型组成的联合类型;

注意:如果[]中的key有不存在T中的,则是any;因为ts也不知道该key最终是什么类型,所以是any;且也会报错。

c. & 交叉类型注意点

交叉类型取的多个类型的并集,但是如果相同key但是类型不同,则该keynever

interface Eg1 {
    name:string,
    age:number
}

interface Eg2 {
    name:string,
    age:string,
    color: string,
}

上面两个接口定义的name,age属性名是相同的,但是属性的类型并不相同:

type T = Eg1 & Eg2

T的类型为 {name: string; age: never; color: string}

注意:age因为Eg1和Eg2中的类型不一致,所以交叉后age的类型是never

d. extends关键词特性(重点)

  • 用于接口,表示继承
 interface T1 {
  name: string,
}

interface T2 {
  sex: number,
}

/**
 * @example
 * T3 = {name: string, sex: number, age: number}
 */
interface T3 extends T1, T2 {
  age: number,
}

注意:接口支持多重继承,语法为逗号隔开。如果是type实现继承,则可以使用交叉类型type A = B & C & D

  • 表示条件类型,可用于条件判断

表示条件判断,如果前面的条件满足,则返回问号后的第一个参数,否则第二个。类似于js的三元运算。

/**
 * @example
 * type A1 = 1
 */
type A1 = 'x' extends 'x' ? 1 : 2;

/**
 * @example
 * type A2 = 2
 */
type A2 = 'x' | 'y' extends 'x' ? 1 : 2;

/**
 * @example
 * type A3 = 1 | 2
 */
type P<T> = T extends 'x' ? 1 : 2;
type A3 = P<'x' | 'y'>

**提问:**为什么 A2A3 的值不一样?

  • 如果用于简单的条件判断,则是直接判断前面的类型是否可分配给后面的类型
  • 若extends前面的类型是泛型,且泛型传入的是联合类型时,则会依次判断该联合类型的所有子类型是否可分配给extends后面的类型(是一个分发的过程)。

总结,就是 extends 前面的参数为联合类型时则会分解(依次遍历所有的子类型进行条件判断)联合类型进行判断。然后将最终的结果组成新的联合类型。

如果不想被分解(分发),做法也很简单,可以通过简单的元组类型包裹以下:

type P<T> = [T] extends ['x'] ? 1 : 2;
/**
 * type A4 = 2;
 */
type A4 = P<'x' | 'y'>

条件类型的分布式特性文档

2. 索引访问操作符 []

a. 操作符[]

索引访问操作符也就是[],其实和我们访问对象的某个属性值是一样的语法,但是在 TS 中它可以用来访问某个属性的类型。

b. 案例

  • 例一:
interface Info {
  name: string;
  age: number;
}
type NameType = Info["name"];
let name: NameType = 123; // error 不能将类型“123”分配给类型“string”
 
  • 例二:
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name]; // o[name] is of type T[K]
}

这个函数中,两个参数的类型分别为泛型 T 和 K,而函数的返回值类型为T[K],只要函数的返回值也是这种形式,即访问参数 o 的参数 name 属性,即可。

  • 例三:

与结合接口的例子:

interface Obj<T> {
  [key: number]: T;
}
const key: keyof Obj<number>; // key的类型为number

如果索引类型为 number,那么实现该接口的对象的属性名必须是 number 类型;但是如果接口的索引类型是 string 类型,那么实现该接口的对象的属性名设置为数值类型的值也是可以的,因为数值最后还是会先转换为字符串。这里一样,如果接口的索引类型设置为 string 的话,keyof Obj等同于类型number | string:

  interface Obj<T> {
    [key: string]: T;
  }
  let key: keyof Obj<number>; // key的类型为number | string
  // key = 123; // right
  key = '123'; // right
  • 例四:

也可以使用访问操作符,获取索引签名的类型:

interface Obj<T> {
  [key: string]: T;
}
const obj: Obj<number> = {
  age: 18
};
let value: Obj<number>["age"]; // value的类型是number,也就是name的属性值18的类型
  • 例五:

当tsconfig.json里strictNullChecks设为false时,通过Type[keyof Type]获取到的,是除去never & undefined & null这三个类型之后的字段值类型组成的联合类型,来看例子:

interface Type {
  a: never;
  b: never;
  c: string;
  d: number;
  e: undefined;
  f: null;
  g: object;
}
type test = Type[keyof Type];
// test的类型是string | number | object

strictNullChecks设为true时

  interface Type {
    a: never;
    b: never;
    c: string;
    d: number;
    e: undefined;
    f: null;
    g: object;
  }
  type test = Type[keyof Type];
  // test的类型是string | number | object | null | undefined 
  • 例六:
interface AnyObject {
  [key: string]: number
}
let obj: AnyObject = {
  a: 1,
  b: 2
}
// 对象obj中只能出现为number类型的值
  1. 使用 [key: string] 来约束该接口中允许出现的属性名称。表示只要是string类型的属性名称,都可以出现在对象中。
  2. 这样,对象 obj 中就可以出现任意多个属性(比如,a、b等)。
  3. key 只是一个占位符,可以换成任意合法的变量名称。
  4. 隐藏的前置知识:JS 中对象({})的键是 string 类型的。
  • 例七:

数组对应的泛型接口:

interface MyArray<T> {
  [n: number]: T   // 数组中每一项都是T类型(T是该数组的类型变量)
}

let arr: MyArray<number> = [1, 3, 5]   
// 数组中每一项都是number类型,换句话说,这是一个number[]

  1. MyArray 接口模拟原生的数组接口,并使用 [n: number]来作为索引签名类型。
  2. 该索引签名类型表示:只要是 number 类型的键(索引)都可以出现在数组中,或者说数组中可以有任意多个元素。
  3. 同时也符合数组索引是 number 类型这一前提。

二、映射类型

1. 概述

  • 根据的类型创建出的类型, 我们称之为映射类型。
  • 注意:映射类型只能在类型别名中使用,不能在接口中使用。

2. 基础案例

案例一 根据联合类型创建新类型:

根据联合类型创建新类型:

// 类型 ProKeys 有x/y/z,另一个类型Type1中也有x/y/z,并且Type1中的x/y/z类型相同
type ProKeys = 'x' | 'y' | 'z';

// 现在这种书写方式相当于x/y/z重复书写了两次。
type Type1 = {x: number; y:number; z:number}

上面这种情况就可以使用映射类型来进行简化:

type ProKeys = 'x' | 'y' | 'z';
type Type2 = {[Key in ProKeys]:number}
  1. 映射类型是基于索引签名类型的,所以该语法也使用了 []
  2. Key in ProKeys 表示 Key 可以是PorKeys 联合类型中的任意一个
  3. 使用映射类型创建的新对象 Type2 和 Type1 结构完全相同
案例二 根据对象类型创建新类型:

根据对象类型创建新类型:

type Props = {a: number; b: string; c: boolean};
type Type3 = {[key in keyof Props]: number}
// 相当于
type Type3 = {a: number; b: number; c: number};
  1. 首先,先执行 keyof Props 获取对象类型 Props所有建的联合类型(‘a’|‘b’|‘c’)
  2. 然后,key in …就表示Key可以是Props中所有的键名称中的任意一个。
案例三 keyof和映射类型的例子:

我们可以使用这个接口实现一个有且仅有一个 age 属性的对象,但如果我们想再创建一个只读版本的同款对象,那我们可能需要再重新定义一个接口,然后让 age 属性 readonly。如果接口就这么简单,你确实可以这么做,但是如果属性多了,而且这个结构以后会变,那就比较麻烦了。这种情况我们可以使用映射类型,下面来看例子:

interface Info {
  age: number;
}
type ReadonlyType<T> = { readonly [P in keyof T]: T[P] }; // 这里定义了一个ReadonlyType<T>映射类型
type ReadonlyInfo = ReadonlyType<Info>;
let info: ReadonlyInfo = {
  age: 18
};
info.age = 28; // error Cannot assign to 'age' because it is a constant or a read-only property

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端
这个例子展示了如何通过一个普通的接口创建一个每个属性都只读的接口,这个过程有点像定义了一个函数,这个函数会遍历传入对象的每个属性并做处理。同理你也可以创建一个每个属性都是可选属性的接口:

  interface Info {
    age: number;
  }
  type ReadonlyType<T> = { readonly [P in keyof T]?: T[P] };
  type ReadonlyInfo = ReadonlyType<Info>;
  let info: ReadonlyInfo = {age: 18};
  console.log(info)

注意 :

这里用到了一个新的操作符 in,TS 内部使用了 for … in,定义映射类型,这里涉及到三个部分:

  • 类型变量,也就是上例中的 P,它就像 for … in 循环中定义的变量,用来在每次遍历中绑定当前遍历到的属性名;
  • 属性名联合,也就是上例中 keyof T,它返回对象 T 的属性名联合;
  • 属性的结果类型,也就是 T[P]

实际上,TS 内置了这两种映射类型,泛型工具类型(比如,Partial< Type>、Record<Keys,Type>)

type Pick<T, K extends keyof T> = { [P in K]: T[P] };
// 上面语句的意思是 keyof T 拿到 T 所有属性名,然后 in 进行遍历,将值赋给 P,最后 T[P] 取得相应属性的值
type Record<K extends keyof any, T> = { [P in K]: T };
 
案例四 Pick:

Pick 例子:

interface Info {
  name: string;
  age: number;
  address: string;
}
const info: Info = {
  name: "lison",
  age: 18,
  address: "beijing"
};
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> { // 这里我们定义一个pick函数,用来返回一个对象中指定字段的值组成的对象
  let res = {} as Pick<T, K>;
  keys.forEach(key => {
    res[key] = obj[key];
  });
  return res;
}
const nameAndAddress = pick(info, ["name", "address"]); // { name: 'lison', address: 'beijing' }
案例五 Record:

Record例子:

它适用于将一个对象中的每一个属性转换为其他值的场景。

function mapObject<K extends string | number, T, U>(
  obj: Record<K, T>,
  f: (x: T) => U
): Record<K, U> {
  let res = {} as Record<K, U>;
  for (const key in obj) {
    res[key] = f(obj[key]);
  }
  return res;
}
 
const names = { 0: "hello", 1: "world", 2: "bye" };
const lengths = mapObject(names, s => s.length); // { 0: 5, 1: 5, 2: 3 }

我们输入的对象属性值为字符串类型,输出的对象属性值为数值类型。

案例六 Partial:

Partial< Type >的实现:

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

type Props = {a: number; b: string; c: boolean};
type PartialProps = Partial<Props>
  1. keyof T 即 keyof Props 表示获取 Props的所有键,也就是:‘a’|‘b’|‘c’
  2. 在 [] 后面添加 ?(问号),表示将这些属性变为可选的,以此来实现Partial的功能
  3. 冒号后面的T[P]表示获取T中每个键对应的类型,比如:a 对应的 是 number
  4. 最终,新类型 PartialProps 和旧类型 Props 结构完全相同,只是让所有类型都变成可选了。
案例七 keyof 和映射类型支持用 number 和 symbol 命名的属性的例子:

keyof 和映射类型支持用 number 和 symbol 命名的属性的例子:

const stringIndex = "a";
const numberIndex = 1;
const symbolIndex = Symbol();
type Obj = {
  [stringIndex]: string;
  [numberIndex]: number;
  [symbolIndex]: symbol;
};
type keys = keyof Obj;
let key: keys = 2; // error
let key: keys = 1; // right
let key: keys = "b"; // error
let key: keys = "a"; // right
let key: keys = Symbol(); // error
let key: keys = symbolIndex; // right
const stringIndex = "a";
const numberIndex = 1;
const symbolIndex = Symbol();
type Obj = {
  [stringIndex]: string;
  [numberIndex]: number;
  [symbolIndex]: symbol;
};
type ReadonlyType<T> = { readonly [P in keyof T]?: T[P] };
let obj: ReadonlyType<Obj> = {
  a: "aa",
  1: 11,
  [symbolIndex]: Symbol()
};
obj.a = "bb"; // error Cannot assign to 'a' because it is a read-only property
obj[1] = 22; // error Cannot assign to '1' because it is a read-only property
obj[symbolIndex] = Symbol(); // error Cannot assign to '[symbolIndex]' because it is a read-only property
案例八 元组和数组上的映射类型:

元组和数组上的映射类型:

在元组和数组上的映射类型会生成新的元组和数组,并不会创建一个新的类型,这个类型上会具有 push、pop 等数组方法和数组属性。来看例子:

type MapToPromise<T> = { [K in keyof T]: Promise<T[K]> };
type Tuple = [number, string, boolean];
type promiseTuple = MapToPromise<Tuple>;
let tuple: promiseTuple = [
  new Promise((resolve, reject) => resolve(1)),
  new Promise((resolve, reject) => resolve("a")),
  new Promise((resolve, reject) => resolve(false))
];

这个例子中定义了一个MapToPromise映射类型。它返回一个将传入的类型的所有字段的值转为Promise,且Promise的resolve回调函数的参数类型为这个字段类型。我们定义了一个元组Tuple,元素类型分别为number、string和boolean,使用MapToPromise映射类型将这个元组类型传入,并且返回一个promiseTuple类型。当我们指定变量tuple的类型为promiseTuple后,它的三个元素类型都是一个Promise,且resolve的参数类型依次为number、string和boolean。

2.1 同态

两个相同类型的代数结构之间的结构保持映射。

这四个内置映射类型中,Readonly、Partial 和 Pick 是同态的,而 Record 不是,因为 Record 映射出的对象属性值是新的,和输入的值的属性值不同。

3. 索引查询类型

T[P]语法,在TS中叫做索引查询(访问)类型,用于查询属性的类型。

type Props = {a: number; b: string; c: boolean};
type TypeA = Props['a'];
// 相当于
type TypeA = number;
  • Props[‘a’] 表示查询类型 Props 中属性 a 对应的类型 number。
  • 注意:[] 中的属性必须存在于被查询类型中,否则就会报错。

索引查询类型也可以同时查询多个索引的类型。

type Props = {a: number; b: string; c: boolean};

// 使用字符串字面量的联合类型,获取属性 a 和 b 对应的类型
type TypeA = Props['a' | 'b'];	// string | number

// 使用 keyof 操作符获取 Props 中所有键对应的类型
type TypeA = Props[keyof Props];	// string | number | boolean

4. 由映射类型进行推断

还原映射之前的类型, 这种操作我们称之为 拆包

type Proxy<T> = { // 这里定义一个映射类型,他将一个属性拆分成get/set方法
  get(): T;
  set(value: T): void;
};
type Proxify<T> = { [P in keyof T]: Proxy<T[P]> }; // 这里再定义一个映射类型,将一个对象的所有属性值类型都变为Proxy<T>处理之后的类型
function proxify<T>(obj: T): Proxify<T> { // 这里定义一个proxify函数,用来将对象中所有属性的属性值改为一个包含get和set方法的对象
  let result = {} as Proxify<T>;
  for (const key in obj) {
    result[key] = {
      get: () => obj[key],
      set: value => (obj[key] = value)
    };
  }
  return result;
}
let props = {
  name: "lison",
  age: 18
};
let proxyProps = proxify(props);
console.log(proxyProps.name.get()); // "lison"
proxyProps.name.set("li");
 

我们来看下这个例子,这个例子我们定义了一个函数,这个函数可以把传入的对象的每个属性的值替换为一个包含 get 和 set 两个方法的对象。最后我们获取某个值的时候,比如 name,就使用 proxyProps.name.get()方法获取它的值,使用 proxyProps.name.set()方法修改 name 的值。

接下来我们来看如何进行拆包:

function unproxify<T>(t: Proxify<T>): T { // 这里我们定义一个拆包函数,其实就是利用每个属性的get方法获取到当前属性值,然后将原本是包含get和set方法的对象改为这个属性值
  let result = {} as T;
  for (const k in t) {
    result[k] = t[k].get(); // 这里通过调用属性值这个对象的get方法获取到属性值,然后赋给这个属性,替换掉这个对象
  }
  return result;
}
let originalProps = unproxify(proxyProps);
 

5. 增加或移除特定修饰符

映射类型增加了增加或移除特定修饰符的能力,使用+和-符号作为前缀来指定增加还是删除修饰符。首先来看我们如何通过映射类型为一个接口的每个属性增加修饰符,我们这里使用+前缀:

interface MyInterface {
    name: string;
    age: number;
}

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

type test = MyType<MyInterface>;

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

type test2 = UnMyType<test>;

映射类型增加了增加或移除特定修饰符的能力,使用+和-符号作为前缀来指定增加还是删除修饰符。

首先来看我们如何通过映射类型为一个接口的每个属性增加修饰符,我们这里使用+前缀:

interface Info {
  name: string;
  age: number;
}
type ReadonlyInfo<T> = { +readonly [P in keyof T]+?: T[P] };
let info: ReadonlyInfo<Info> = {
  name: "lison"
};
info.name = ""; // error

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端

ReadonlyInfo创建的接口类型,属性是可选的,所以我们在定义 info 的时候没有写 age 属性也没问题,同时每个属性是只读的,所以我们修改 name 的值的时候报错。我们通过+前缀增加了 readonly 和?修饰符。当然,增加的时候,这个+前缀可以省略,也就是说,上面的写法和type ReadonlyInfo = { readonly [P in keyof T]?: T[P] }是一样的。我们再来看下怎么删除修饰符:

interface Info {
  name: string;
  age: number;
}
type RemoveModifier<T> = { -readonly [P in keyof T]-?: T[P] };
type InfoType = RemoveModifier<Readonly<Partial<Info>>>;
let info1: InfoType = {
  // error missing "age"
  name: "lison"
};
let info2: InfoType = {
  name: "lison",
  age: 18
};
info2.name = ""; // right, can edit

这个例子我们定义了去掉修饰符的映射类型 RemoveModifier,Readonly<Partial>则是返回一个既属性可选又只读的接口类型,所以 InfoType 类型则表示属性必含而且非只读。

TS 内置了一个映射类型Required,使用它可以去掉 T 所有属性的?修饰符。

6. 重映射

重映射就是在索引后加一个 as 语句,表明索引转换成什么,它可以用来对索引类型做过滤和转换。

返回 never 代表过滤掉,否则保留。

 type person ={
  name:'lisi',
  age:20,
  gender:true,
 }
// 比如过滤出类型为 string 的索引:
 type FilterString<T> = {
  [Key in keyof T as T[Key] extends string ? Key: never]: T[Key];
}
type res =FilterString<person>

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端
还可以对索引做转换,比如修改索引名,加上 get:

 type person ={
  name:'lisi',
  age:20,
  gender:true,
 }

type Getters<T extends Record<any, any>> = {
  [Key in keyof T as `get${Capitalize<Key & string>}`]: T[Key];
}
type res =Getters<person>

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端
T extends xxx 是给类型参数的约束,表示只能传入这种类型。这里的 Record 类型是生成索引类型的,我们上面介绍过,所以 T extends Record<any, any> 就是约束了这里只能传入索引类型。

as 后面是把索引转换成什么,我们是在原来的基础上做了修改,加上了 get,并且后面内容首字母大写,这个 Capitalize 也是 TS 内置的类型。

这两个例子分别说明了 重映射 as 可以用来做索引类型的过滤和转换,可以对索引类型做更灵活的编程。

实现 key 和 value 的互换:

type person ={
  name:'lisi',
  age:20,
  gender:true,
 }

 type Flip<T extends Record<any, any>> = {
  [Key in keyof T as `${T[Key]}`]: Key
}
type res =Flip<person>

TypeScript 学习笔记(六):索引签名类型、映射类型,TypeScript,typescript,学习,笔记,前端
支持重映射之后,映射类型可以对索引类型做更多的修改。文章来源地址https://www.toymoban.com/news/detail-581084.html

到了这里,关于TypeScript 学习笔记(六):索引签名类型、映射类型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript 学习笔记(四):类型守卫

    类型守卫的作用在于触发类型缩小。实际上,它还可以用来区分类型集合中的不同成员 类型守卫包括switch、字面量恒等、typeof、instanceof、in 和自定义类型守卫 简单说当一个类型是多种可能时例如’any’,‘unknown’,‘联合类型’ 等在逻辑判断时候要具体到其唯一子集可能性

    2024年02月15日
    浏览(55)
  • TypeScript 学习笔记(七):条件类型

    TS中的条件类型就是在类型中添加条件分支,以支持更加灵活的泛型,满足更多的使用场景。内置条件类型是TS内部封装好的一些类型处理,使用起来更加便利。 当T类型可以赋值给U类型时,则返回X类型,否则返回Y类型。 T U X Y 四个是占位符,分别表示四种类型; T extends U

    2024年02月17日
    浏览(40)
  • TypeScript 学习笔记(一):基本类型、交叉类型、联合类型、类型断言

    TS中实现对象属性必选、对象属性在开发过程中十分常见,前端在传参数时,有些参数比必传,有些是选传,我们可以定一个多个对象来实现传参,但是这让代码变得冗余。我们可以通过TS定义数据类型来实现。 TypeScript中文网 1. 数组 2. 布尔 3. 数值 当我们给num赋值为123但没有

    2024年02月15日
    浏览(45)
  • TypeScript 学习笔记(二):接口与类型别名、字面量类型

    在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些

    2024年02月16日
    浏览(40)
  • TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型

    JavaScript的变量类型相当于是动态类型,可以跟随着赋值的改变而类型改变,函数的参数也没有设定类型,所以在定位错误以及安全性上不太够。 说明 1.TS不能被JS解析器直接执行,需要编译成JS执行 2.即使TS编译出错也可以编译成JS 1.TypeScript是什么? TypeScript 是类型安全的Ja

    2024年02月16日
    浏览(75)
  • TypeScript中的keyof、typeof、索引访问类型、条件类型

    TypeScript中的keyof类型操作符 可以获取某个类型的所有属性名组成的联合类型 。这个操作符的作用是帮助开发者在静态类型检查中更准确地操作属性名。 举例来说,如果我们有如下一个接口: 我们可以使用keyof来获取这个接口的属性名联合类型: 有了属性名联合类型,我们可

    2024年02月11日
    浏览(53)
  • TypeScript报错:ts(2683)“this“ 隐式具有类型 “any“,因为它没有类型注释。ts(7009)其目标缺少构造签名的 “new“ 表达式隐式具有 “any“ 类型。

    TypeScript报错:ts(2683)“this” 隐式具有类型 “any”,因为它没有类型注释。 例: 可以改为 TypeScript报错:ts(7009)其目标缺少构造签名的 “new” 表达式隐式具有 “any” 类型。 例: 可以改为:

    2024年02月16日
    浏览(69)
  • 前端TypeScript学习day02-TS常用类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 TypeScript 常用类型 接口  元组  类型推论 类型断言 字面量类型 枚举 any 类型 typeof  当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到

    2024年02月08日
    浏览(52)
  • 前端TypeScript学习day03-TS高级类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)            目录 TypeScript 高级类型 class 类 class继承  extends implements  类成员可见性  public  protected  private   readonly 兼容性 类型兼容性 接口兼容性  函数兼容性  TypeScri

    2024年02月08日
    浏览(37)
  • 前端TypeScript学习day04-交叉类型与泛型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)            目录 交叉类型 泛型 创建泛型函数 调用泛型函数: 简化调用泛型函数: 泛型约束  指定更加具体的类型 添加约束  泛型接口  泛型类 泛型工具类型  Partial 

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包