在打字稿中合并类型(将键添加到现有的 keyof 类型)
Merging types in typescript (adding keys to an existing keyof type)
如果我有一个由键组成的打字稿类型:
const anObject = {value1: '1', value2: '2', value3: '3'}
type objectKeys = keyof typeof anObject
然后我希望向该类型添加键,同时保留当前键,我该怎么做?
例如,如果我想将键 'get_value1'、'get_value2'、'get_value3' 添加到类型 'objectKeys'
最后,我想要一个看起来像这样的类型:
type objectKeys = keyof anObject + 'get_value1', 'get_value2', 'get_value3'
无需手动定义前缀为 'get_' 的键,我知道我可以键入键来创建此对象 - 但这对我的用例来说不可行。我只是想向类型 'objectKeys'
添加一些可能存在或可能不存在的键
我也知道我可以创建一个泛型或任何允许任何键值的类型,但是我必须知道实际的键名。允许请求对象的任何密钥对我没有帮助,我需要现有密钥 + 我想添加的密钥。
感谢您的帮助。
为清楚起见添加:
const anObject = {val1: '1', val2: '2'}
type objectKeys = keyof typeof anObject
Object.keys(anObject).forEach(key => {
const getAddition = `get_${key}`
anObject[getAddition] = getAddition
})
// now I don't know whats next, how do I update objectKeys to include the
// additions added in the forEach loop.
// What I really want is to not have to add the 'get' values to the object
// at all, JUST to the type. I want typechecking for the get values that
// may or may not actually exist on the object.
希望这样更清楚。
听起来你在要求 concatenation of string literal types:也就是说,你希望能够获取字符串文字 "get_"
和另一个字符串文字 "value1"
,并具有TypeScript 知道,如果你连接这些类型的字符串,你会得到一个 "get_value1"
类型的字符串。不幸的是,此功能在 TypeScript 2.4 中不存在(并且可能在 2.5 或 2.6 中也不存在)。
因此无法满足您的要求并保持严格的类型安全。当然,您可以放松类型安全并允许访问任何未知密钥:
const anObject = {val1: '1', val2: '2'};
const openObject: { [k: string]: any } & typeof anObject = anObject;
// replace "any" above with whatever type the get_XXX values are
Object.keys(openObject).forEach(key => {
const getAddition = `get_${key}`
openObject[getAddition] = getAddition
})
openObject.val1 = 1; // error, val1 is known to be a string
openObject.get_val1 = 1; // no error, get_val1 is any
openObject.gut_val4 = 1; // no error, oops, sorry
但你说你不想那样做。
在这种情况下,我的建议是放弃向对象添加任意键,而是让 getter(或任何它们)挂在一个 get
属性,像这样:
const anObject = { val1: '1', val2: '2' }
type AnObject = typeof anObject;
type ObjectKeys = keyof AnObject;
type GetAugmentedObject = AnObject & { get: Record<ObjectKeys, any> };
// replace "any" above with whatever type the get.XXX values are
const get = {} as GetAugmentedObject['get'];
Object.keys(anObject).forEach((key: ObjectKeys) => get[key] = key);
const augmentedObject: GetAugmentedObject = { ...anObject, get }
augmentedObject.val1; // ok
augmentedObject.val2; // ok
augmentedObject.get.val1; // ok
augmentedObject.get.val2; // ok
augmentedObject.get.val3; // error, no val3
augmentedObject.git.val1; // error, no git
这对开发人员来说并没有太大的不同(obj.get.val1
与 obj.get_val1
),但对 TypeScript 的跟进能力有很大的不同。如果您可以控制添加键的代码,我强烈建议您做一些像这样对 TypeScript 友好的事情,因为如果没有必要,您不想花时间与 TypeScript 打交道。
否则,如果只有类型级别的字符串连接对您有用,并且您觉得您的用例足够引人注目,也许您应该去 the relevant GitHub issue 并给它一个并描述为什么它是必须的-有给你。
希望对您有所帮助。祝你好运!
2020 更新
打字稿里有 v4.1.0
你可能需要这个 - https://github.com/microsoft/TypeScript/pull/40336
您可以使用模板文字。
这是一个示例,其中 属性 id
必须是 #
+ key
:
interface MyInterface<K extends string> {
something: {
[key in K]: { id: `#${key}` }
}
}
所以以下是正确的:
let x: MyInterface<'foo'> = {
something: {
foo: { id: '#foo' }
}
}
但这是不正确的:
let y: MyInterface<'foo'> = {
something: {
foo: { id: 'foo' }
}
}
如果我有一个由键组成的打字稿类型:
const anObject = {value1: '1', value2: '2', value3: '3'}
type objectKeys = keyof typeof anObject
然后我希望向该类型添加键,同时保留当前键,我该怎么做?
例如,如果我想将键 'get_value1'、'get_value2'、'get_value3' 添加到类型 'objectKeys'
最后,我想要一个看起来像这样的类型:
type objectKeys = keyof anObject + 'get_value1', 'get_value2', 'get_value3'
无需手动定义前缀为 'get_' 的键,我知道我可以键入键来创建此对象 - 但这对我的用例来说不可行。我只是想向类型 'objectKeys'
添加一些可能存在或可能不存在的键我也知道我可以创建一个泛型或任何允许任何键值的类型,但是我必须知道实际的键名。允许请求对象的任何密钥对我没有帮助,我需要现有密钥 + 我想添加的密钥。
感谢您的帮助。
为清楚起见添加:
const anObject = {val1: '1', val2: '2'}
type objectKeys = keyof typeof anObject
Object.keys(anObject).forEach(key => {
const getAddition = `get_${key}`
anObject[getAddition] = getAddition
})
// now I don't know whats next, how do I update objectKeys to include the
// additions added in the forEach loop.
// What I really want is to not have to add the 'get' values to the object
// at all, JUST to the type. I want typechecking for the get values that
// may or may not actually exist on the object.
希望这样更清楚。
听起来你在要求 concatenation of string literal types:也就是说,你希望能够获取字符串文字 "get_"
和另一个字符串文字 "value1"
,并具有TypeScript 知道,如果你连接这些类型的字符串,你会得到一个 "get_value1"
类型的字符串。不幸的是,此功能在 TypeScript 2.4 中不存在(并且可能在 2.5 或 2.6 中也不存在)。
因此无法满足您的要求并保持严格的类型安全。当然,您可以放松类型安全并允许访问任何未知密钥:
const anObject = {val1: '1', val2: '2'};
const openObject: { [k: string]: any } & typeof anObject = anObject;
// replace "any" above with whatever type the get_XXX values are
Object.keys(openObject).forEach(key => {
const getAddition = `get_${key}`
openObject[getAddition] = getAddition
})
openObject.val1 = 1; // error, val1 is known to be a string
openObject.get_val1 = 1; // no error, get_val1 is any
openObject.gut_val4 = 1; // no error, oops, sorry
但你说你不想那样做。
在这种情况下,我的建议是放弃向对象添加任意键,而是让 getter(或任何它们)挂在一个 get
属性,像这样:
const anObject = { val1: '1', val2: '2' }
type AnObject = typeof anObject;
type ObjectKeys = keyof AnObject;
type GetAugmentedObject = AnObject & { get: Record<ObjectKeys, any> };
// replace "any" above with whatever type the get.XXX values are
const get = {} as GetAugmentedObject['get'];
Object.keys(anObject).forEach((key: ObjectKeys) => get[key] = key);
const augmentedObject: GetAugmentedObject = { ...anObject, get }
augmentedObject.val1; // ok
augmentedObject.val2; // ok
augmentedObject.get.val1; // ok
augmentedObject.get.val2; // ok
augmentedObject.get.val3; // error, no val3
augmentedObject.git.val1; // error, no git
这对开发人员来说并没有太大的不同(obj.get.val1
与 obj.get_val1
),但对 TypeScript 的跟进能力有很大的不同。如果您可以控制添加键的代码,我强烈建议您做一些像这样对 TypeScript 友好的事情,因为如果没有必要,您不想花时间与 TypeScript 打交道。
否则,如果只有类型级别的字符串连接对您有用,并且您觉得您的用例足够引人注目,也许您应该去 the relevant GitHub issue 并给它一个并描述为什么它是必须的-有给你。
希望对您有所帮助。祝你好运!
2020 更新
打字稿里有 v4.1.0
你可能需要这个 - https://github.com/microsoft/TypeScript/pull/40336
您可以使用模板文字。
这是一个示例,其中 属性 id
必须是 #
+ key
:
interface MyInterface<K extends string> {
something: {
[key in K]: { id: `#${key}` }
}
}
所以以下是正确的:
let x: MyInterface<'foo'> = {
something: {
foo: { id: '#foo' }
}
}
但这是不正确的:
let y: MyInterface<'foo'> = {
something: {
foo: { id: 'foo' }
}
}