TS-元组转换为对象
TS-元组转换为对象
传入一个元组类型,将这个元组类型转换为对象类型,这个对象类型的键/值都是从元组中遍历出来。
例如:
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
const result: TupleToObject<typeof tuple>
// expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
一、关键词说明
元组
在 TypeScript 中,元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
元祖可以确定元素数据类型,但不要超出范围,可以把元祖理解为固定长度,超出范围不能保证其类型。
typeof 关键字
在 TypeScript 中,typeof
操作符可以用来获取一个变量或对象的类型。
interface People {
name: string;
age: number;
}
const me: People = { name: "zzk", age: 23 };
type Me = typeof me; // type Me = People
在上面代码中,我们通过 typeof
操作符获取 me 变量的类型并赋值给 Me 类型变量,之后我们就可以使用 Me 类型:
const oneGod: Me = { name: "one", age: 24 }
你也可以对嵌套对象执行相同的操作:
const otherPeople = {
name: "one",
age: 24,
address: {
province: '山东',
city: '青岛'
}
}
type OtherPeople = typeof otherPeople;
/*
type OtherPeople = {
name: string;
age: number;
address: {
province: string;
city: string;
};
}
*/
此外,typeof
操作符除了可以获取对象的结构类型之外,它也可以用来获取函数对象的类型,比如:
function toArray(x: number): Array<number> {
return [x];
}
type Func = typeof toArray; // -> (x: number) => number[]
as 关键字
有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。
类型断言有两种形式。 其一是“尖括号”语法:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
另一个为as
语法:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
两种形式都有同样的效果;然而,当你在TypeScript里使用JSX时,只有 as
语法断言是被允许的。
const 断言
TypeScript 3.4 引入了一种新的字面量构造方式,也称为 const 断言。当我们使用 const 断言构造新的字面量表达式时,我们可以向编程语言发出以下信号:
- 表达式中的任何字面量类型都不应该被扩展;
- 对象字面量的属性,将使用
readonly
修饰; - 数组字面量将变成
readonly
元组。
下面我们来举一个 const 断言的例子:
let x = "hello" as const;
type X = typeof x; // type X = "hello"
let y = [10, 20] as const;
type Y = typeof y; // type Y = readonly [10, 20]
let z = { text: "hello" } as const;
type Z = typeof z; // let z: { readonly text: "hello"; }
数组字面量应用 const 断言后,它将变成 readonly
元组,之后我们还可以通过 typeof
操作符获取元组中元素值的联合类型,具体如下:
type Data = typeof y[number]; // type Data = 10 | 20
这同样适用于包含引用类型的数组,比如包含普通的对象的数组。这里我们也来举一个具体的例子:
const locales = [
{
locale: "zh-CN",
language: "中文"
},
{
locale: "en",
language: "English"
}
] as const;
// type Locale = "zh-CN" | "en"
type Locale = typeof locales[number]["locale"];
另外在使用 const 断言的时候,我们还需要注意以下两个注意事项:
const
断言只适用于简单的字面量表达式
// A 'const' assertions can only be applied to references to enum members,
// or string, number, boolean, array, or object literals.
let a = (Math.random() < 0.5 ? 0 : 1) as const; // error
let b = Math.random() < 0.5 ? 0 as const :
1 as const;
const
上下文不会立即将表达式转换为完全不可变
let arr = [1, 2, 3, 4];
let foo = {
name: "foo",
contents: arr,
} as const;
foo.name = "bar"; // error!
foo.contents = []; // error!
foo.contents.push(5); // ...works!
二、元组使用方式
定义一对值分别为 string
和 number
的元组:
let tom: [string, number] = ['Tom', 25];
当赋值或访问一个已知索引的元素时,会得到正确的类型:
let tom: [string, number];
tom[0] = 'Tom';
tom[1] = 25;
tom[0].slice(1);
tom[1].toFixed(2);
也可以只赋值其中一项:
let tom: [string, number];
tom[0] = 'Tom';
但是当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项。
let tom: [string, number];
tom = ['Tom', 25];
let tom: [string, number];
tom = ['Tom'];
// Property '1' is missing in type '[string]' but required in type '[string, number]'.
越界的元素
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
let tom: [string, number];
tom = ['Tom', 25];
tom.push('male');
tom.push(true);
// Argument of type 'true' is not assignable to parameter of type 'string | number'.
三、题解
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
//readonly , extends : 当使用了 `const` 字面量代表对象字面量的属性,将使用 `readonly` 修饰,数组字面量将变成 `readonly` 元组,表达式中的任何字面量类型都不应该被扩展
//[K in T[number]] 对数组里每个index进行循环将index转换成key
type TupleToObject<T extends readonly any[]> = { [K in T[number]]: K }
const result: TupleToObject<typeof tuple>
// expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
转载自:https://juejin.cn/post/7005376185278414861