简体   繁体   English

Typescript type 用于两种具有相同键和相似值的类型

[英]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:让我们分解一下:

  1. [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中的特定键,例如foobar等。
  2. 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原始值导出,所以...
  3. 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'

Playground 操场

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在打字稿中合并类型(将键添加到现有的 keyof 类型) - Merging types in typescript (adding keys to an existing keyof type) react 如何区分具有相同父级的两个 arrays 的相似键? - How does react differentiate similar keys for two arrays with same parent? 如何根据同一类型中提到的键在打字稿中声明类型? - How to declare a type in typescript based on the keys mentioned in the same type? 如何遍历映射并将具有相似值的键推送到同一个数组中? - How to iterate through map and push keys with similar values into the same array? TypeScript - 遍历字典类型中的类型并创建具有转换值的类型 - TypeScript - iterate over types in a dictionary type and create a type with transformed values 从 JSON 对象中选择值,其中 Typescript 类型的键 - Pick Values from JSON Object Where Keys in Typescript Type Typescript:从 Object 键和数组字符串值生成类型 - Typescript: Generate Type from Object keys and Array string values “pick”函数的 TypeScript 泛型类型(结果对象值类型) - TypeScript generic type for "pick" function (result object values types) JavaScript:如何使用两个相同的键迭代对象(并获得两个值) - JavaScript: How to iterate object with two the same keys (and get two values) Typescript- object 具有动态和预定义键,但具有不同类型作为值(或: object 具有“其余键”的定义) - Typescript- object with both dynamic and pre-defined keys, but with different types as values (or: object with a definition to the “rest-of-the-keys”)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM