class 中 keyof 的模板文字
Template literal from keyof in class
我正在尝试同时组合一堆 TypeScript 功能。
我创建了一个 class,它是用一个对象初始化的,并且有一堆函数,这些函数应该只能将那个对象的键作为参数。到目前为止,一切都很好。 ,我的基本设置如下所示:
class MyClass<Type> {
properties: Partial<Type> = {};
constructor(properties: Type) {
this.properties = properties;
}
pick(...propNames: Array<keyof Type>) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {} as Partial<Type>);
}
}
但我实际上想要 密钥本身,以及这些密钥的略微修改版本被接受——具体来说,"key"
和 "key!"
。在我的例子中,如果您向密钥附加感叹号,则该(可接受的)输入用于指示需要该密钥。
我在手册中找到template literals,发现我可以这样做:
type Name = 'John';
type BangName = `${Name}!`;
完美!但是,我不知道如何将它集成到我的用例中,其中第一种类型是从 keyof
生成的,并且这种集成发生在 JS class.
中
我看到了 ,接近了。它表明我可以做类似下面的事情,它生成一个组合接口,我可以使用 keyof
:
从中导出可接受的密钥
type BangType = {
[Key in keyof Type as `${Key}!`]: Type[Key];
}
type CombinedType = Type & BangType;
然后:
pick(...propNames: Array<keyof CombinedType>) {
但我不知道在哪里我可以生成这个CombinedType
,因为通用Type
在 class 签名中定义。这可能吗?
以下似乎不起作用:
pick(...propNames: Array<keyof PropType> | Array<Key in keyof PropType as `${Key}!`>)
你确实可以在这里使用template literal types。如果您希望 propNames
是 keyof T
或“如果将 "!"
附加到 keyof T
中字符串的末尾所获得的字符串”的数组,则类型你要找的是
Array<keyof T | `${Extract<keyof T, string>}!`>
请注意,由于 T
是一些 generic type you don't control, it's possible for it to have some symbol
-valued keys. And since keyof T
may have symbol
s in it,如果您尝试直接编写模板文字类型 `${keyof T}!`
,编译器将不高兴,因为模板文字类型只能序列化string
s 和 number
s(呃,bigint
s,boolean
s,null
和 undefined
。仅此而已):
oops(...propNames: Array<keyof T | `${keyof T}!`>) { } // error!
// ---------------------------------> ~~~~~~~
// 'symbol' is not assignable to 'string | number | bigint | boolean | null | undefined'.
因为我们只对 T
的 string
值键感兴趣,所以我们使用 the Extract<T, U>
utility type 来获取这些键。然后编译器不会抱怨:
pick(...propNames: Array<keyof T | `${Extract<keyof T, string>}!`>) {
return propNames.map(k =>
typeof k === "string" ? k.replace(/!$/, "") as keyof T : k
).reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {} as Partial<T>);
}
让我们确保它有效:
const n = new MyClass({ a: 1, b: "two", c: true });
const x = n.pick("b!");
console.log(x) // {b: "two"}
看起来不错!
我正在尝试同时组合一堆 TypeScript 功能。
我创建了一个 class,它是用一个对象初始化的,并且有一堆函数,这些函数应该只能将那个对象的键作为参数。到目前为止,一切都很好。
class MyClass<Type> {
properties: Partial<Type> = {};
constructor(properties: Type) {
this.properties = properties;
}
pick(...propNames: Array<keyof Type>) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {} as Partial<Type>);
}
}
但我实际上想要 密钥本身,以及这些密钥的略微修改版本被接受——具体来说,"key"
和 "key!"
。在我的例子中,如果您向密钥附加感叹号,则该(可接受的)输入用于指示需要该密钥。
我在手册中找到template literals,发现我可以这样做:
type Name = 'John';
type BangName = `${Name}!`;
完美!但是,我不知道如何将它集成到我的用例中,其中第一种类型是从 keyof
生成的,并且这种集成发生在 JS class.
我看到了 keyof
:
type BangType = {
[Key in keyof Type as `${Key}!`]: Type[Key];
}
type CombinedType = Type & BangType;
然后:
pick(...propNames: Array<keyof CombinedType>) {
但我不知道在哪里我可以生成这个CombinedType
,因为通用Type
在 class 签名中定义。这可能吗?
以下似乎不起作用:
pick(...propNames: Array<keyof PropType> | Array<Key in keyof PropType as `${Key}!`>)
你确实可以在这里使用template literal types。如果您希望 propNames
是 keyof T
或“如果将 "!"
附加到 keyof T
中字符串的末尾所获得的字符串”的数组,则类型你要找的是
Array<keyof T | `${Extract<keyof T, string>}!`>
请注意,由于 T
是一些 generic type you don't control, it's possible for it to have some symbol
-valued keys. And since keyof T
may have symbol
s in it,如果您尝试直接编写模板文字类型 `${keyof T}!`
,编译器将不高兴,因为模板文字类型只能序列化string
s 和 number
s(呃,bigint
s,boolean
s,null
和 undefined
。仅此而已):
oops(...propNames: Array<keyof T | `${keyof T}!`>) { } // error!
// ---------------------------------> ~~~~~~~
// 'symbol' is not assignable to 'string | number | bigint | boolean | null | undefined'.
因为我们只对 T
的 string
值键感兴趣,所以我们使用 the Extract<T, U>
utility type 来获取这些键。然后编译器不会抱怨:
pick(...propNames: Array<keyof T | `${Extract<keyof T, string>}!`>) {
return propNames.map(k =>
typeof k === "string" ? k.replace(/!$/, "") as keyof T : k
).reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {} as Partial<T>);
}
让我们确保它有效:
const n = new MyClass({ a: 1, b: "two", c: true });
const x = n.pick("b!");
console.log(x) // {b: "two"}
看起来不错!