Typescript多泛型对象声明 [英] Typescript multi generics object declaration

查看:107
本文介绍了Typescript多泛型对象声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图用这种行为键入一个函数:给定具有未定义数量的键的对象 conf ,每个键都是具有 value type 属性的对象,该函数应返回一个具有以下内容的对象:相同的属性,只有 value value 相同.

I'm struggling to type a function with this behaviour : given a object conf with an undefined number of keys, each key being an object with value and type properties, the function should return an object with the same properties and only value as value.

很明显,这是函数输入的示例:

So to be clear, this is an example of function input:

{
  foo: {value: 1, type: 'number'},
  bar: {value: 'hello', type: 'string'}
}

以及相应的输出:

{
  foo: 1,
  bar: 'hello'
}

这是我到目前为止所写的内容:

Here is what I've written so far:

type TypeWithName<T extends string> = 
  T extends 'number' ? number :
  T extends 'boolean' ? boolean : 
  T extends 'undefined' ? undefined :
  T extends 'array' ? string[] :
  string

declare function f<T extends string>(conf: {
  [key: string]: { default: TypeWithName<T>; type: T }
}): { [P in keyof typeof conf]: TypeWithName<T> }

这显然是不正确的,因为:

That is obviously not correct since :

  1. T 一次只能使用一种类型(上面的示例将在属性 bar 上引发错误)
  2. 返回类型具有不确定数量的键,而不是全部和唯一的键存在于输入对象中.
  1. T can only take one type at a time (the example above will throw an error on property bar)
  2. The return type has an undefined number of keys, instead of being all and only keys present in input object.

但是我在这里有点迷失了,我真的不知道在哪里看,也不可能.

But I am a little lost here and don't really know where to look, nor if that's even possible.

推荐答案

我的方法是使用从 type 属性字符串到 value 类型的映射接口,而不是条件类型您也许可以在此处使用条件类型,但是使用类型系统中的接口更容易:

My approach would be to use a mapping interface from type property string to value type instead of a conditional type; you might be able to use a conditional type here but it's easier to work with interfaces in the type system:

interface TypeMap {
  number: number;
  boolean: boolean;
  undefined: undefined;
  string: string;
  object: object | null;
}

我假设您想将"string" 映射到 string ,然后添加了"object" .我想,如果您希望"array" 映射到 string [] ,则可以做到这一点.

I assumed you wanted "string" to map to string, and I added "object". If you want "array" to map to string[] you can do that, I guess.

然后我想使用 TypeMap 创建一个称为 Config 的联合类型,表示 value type ,像这样:

Then I want to use TypeMap to make a union type called Config representing the constraint between value and type, like this:

type Config = {
  [K in keyof TypeMap]: { value: TypeMap[K]; type: K }
}[keyof TypeMap];

如果您进行检查,则等同于:

If you inspect that, it is equivalent to:

type Config = {
    value: number;
    type: "number";
} | {
    value: boolean;
    type: "boolean";
} | {
    value: undefined;
    type: "undefined";
} | {
    value: string;
    type: "string";
} | {
    value: object | null;
    type: "object";
}

现在 f 函数在 T 中是通用的,这是一种对象类型,其键为任意键,其属性为 Config ,由约束表示 Record< T的键,配置> .输入类型为 T ,输出类型为

Now the f function is generic in T, an object type whose keys are whatever and whose properties are Config, represented by the constraint Record<keyof T, Config>. The input type is T, and the output type maps each property in T to its value property:

declare function f<T extends Record<keyof T, Config>>(
  t: T
): { [K in keyof T]: T[K]["value"] };

让我们看看它是否有效:

Let's see if it works:

const output = f({
  foo: { value: 1, type: "number" },
  bar: { value: "hello", type: "string" }
}); 
// const output: { foo: number;  bar: string; }

我认为这就是您期望的输出类型,对吗?如果您需要较窄的类型(例如, foo type 1 而不是 number ),则可以使用 const 断言输入:

I think that's the output type you're expecting, right? If you need a narrower type (where e.g., foo is of type 1 instead of number), you can use a const assertion in the input:

const outputNarrower = f({
  foo: { value: 1, type: "number" },
  bar: { value: "hello", type: "string" }
} as const); 
// const outputNarrower: { foo: 1; bar: "hello"; }

最后,您可以看到对 f()的输入受到限制,因此您不能给出不匹配的 value / type 配对:

Finally, you can see that the input to f() is constrained so that you can't give a mismatching value/type pair:

f({
  chicken: { value: 123, type: "string" }, // error!
  cow: { value: "abc", type: "string" }
});

好的,希望能有所帮助;祝你好运!

Okay, hope that helps; good luck!

查看全文

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆