[英]Typescript type for two types with same keys and similar values
I have a class that take an object as a constructor argument, and I want to enforce a method on the class to accept a very similar object.我有一个 class 将 object 作为构造函数参数,我想在 class 上强制执行一个方法以接受非常相似的 ZA8Z.6331BD59EB6661 The objects have arbitrary keys.对象具有任意键。
For example, constructing with this object:例如,用这个 object 构建:
{
foo: { type: 'A' },
bar: { type: 'B'}
}
I will want the method to only accept objects of a similar form, ie has the same keys and for each key the value type is compatible with the initial object.我希望该方法只接受类似形式的对象,即具有相同的键,并且每个键的值类型与初始 object 兼容。 like:喜欢:
{
foo: SomeARelatedThing,
bar: SomeBRelatedThing
}
I've got a workaround in place where I can at least enforce the same keys, and then do lots of type checking (good to do anyway.) to make sure that the values actually match up.我有一个解决方法,我至少可以强制执行相同的键,然后进行大量类型检查(无论如何都很好。)以确保值实际匹配。
Here's a contrived example from my use case:这是我的用例中的一个人为示例:
type TypeName = 'A' | 'B' | 'C' // ...
class Action<K extends TypeName> {
type: K
constructor(type: K) { this.type = type }
}
type AnyAction = Action<'A'> | Action<'B'> | Action<'C'> // ...
type AProp = { type: 'A' }
type BProp = { type: 'B' }
type CProp = { type: 'C' }
type AnyProp = AProp | BProp | CProp // ...
type PropMap<K extends string> = Record<K, AnyProp>
type ActionMap<K extends string> = Record<K, AnyAction>
class Thing<K extends string> {
props: PropMap<K>
constructor(props: PropMap<K>) { this.props = props }
myMethod<>(actions: ActionMap<K>) { /* ... */ }
}
// type = Thing<'foo' | 'bar'>
const thing = new Thing({
foo: { type: 'A' },
bar: { type: 'B'}
})
// the keys are enforced, but how can the values of foo and bar be enforced, too
thing.myMethod({
foo: new Action('A'),
bar: new Action('B'),
})
I think I would want something more like a type equal to Thing<{foo: 'A', bar: 'B'}>
, but I don't know how to conditionally compute that from a PropMap
-like input to the Thing
constructor, or even if I did, then how would I compute the correct ActionMap
-like type.我想我想要一个更像Thing<{foo: 'A', bar: 'B'}>
类型,但我不知道如何从PropMap
的输入到Thing
构造函数有条件地计算它,或者即使我这样做了,那么我将如何计算正确的ActionMap
类类型。
MyMethod
actually accepts a Partial<ActionMap<K>>
but I don't think that that should matter for what I am asking. MyMethod
实际上接受Partial<ActionMap<K>>
但我认为这对我的要求并不重要。
I think I've got it.我想我明白了。 You need to use mapped types .您需要使用映射类型。
class Thing<K extends string, P extends PropMap<K>> {
props: P
constructor(props: P) { this.props = props }
myMethod(actions: {[Property in keyof P]: Action<P[Property]["type"]>}) { return actions }
}
const thing = new Thing({
foo: { type: 'A' },
bar: { type: 'B'}
})
// the keys are enforced, as well as the corresponding Action types
thing.myMethod({
foo: new Action('A'),
bar: new Action('B'),
})
Note that you need to add the generic P
to your Thing
class, otherwise TypeScript has no way of inferring more detailed information when you instantiate Thing
later.请注意,您需要将通用P
添加到您的Thing
class,否则 TypeScript 无法在您稍后实例化Thing
时推断出更详细的信息。 Basically, you need to set P
to be the same generic type consistently within Thing
otherwise there is no way to differentiate it from the type PropMap
which it extends.基本上,您需要在Thing
中始终将P
设置为相同的泛型类型,否则无法将其与其扩展的类型PropMap
来。
Then, the magic happens in actions: {[Property in keyof P]: Action<P[Property]["type"]>}
.然后,魔术发生在actions: {[Property in keyof P]: Action<P[Property]["type"]>}
。 Let's break it down:让我们分解一下:
[Property in keyof P]:
mapped type index signature. [Property in keyof P]:
映射类型索引签名。 This is what lets us get access to the specific keys in P
, eg foo
, bar
etc.这让我们可以访问P
中的特定键,例如foo
、 bar
等。Action<...>
will set the value corresponding to each key we're mapping in (1.) above to some value, which we want to be an Action
, like Action<'A'>
etc. BUT we want the action to be derived from the original value of P
, so... Action<...>
会将与我们在上面 (1.) 中映射的每个键对应的值设置为某个值,我们希望它是一个Action
,例如Action<'A'>
等。但我们想要这个动作从P
的原始值导出,所以...P[Property]["type"]
let's us access the value from the type
key/value pair from the original type of P
. P[Property]["type"]
让我们从P
的原始类型访问type
键/值对中的值。 Since Property
varies (it's mapped from one type to the other) then for example it becomes foo: P["foo"]["type"]
which is 'A'
, bar: P["bar"]["type"]
which is 'B'
, etc由于Property
不同(它从一种类型映射到另一种类型),因此例如它变为foo: P["foo"]["type"]
即'A'
, bar: P["bar"]["type"]
这是'B'
等
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.