打字稿多泛型对象声明

Typescript multi generics object declaration

我正在努力输入具有这种行为的函数: 给定一个对象 conf 具有未定义数量的键,每个键都是具有 valuetype 属性的对象,该函数应该 return 具有相同属性且仅value 作为 value.

所以要清楚,这是一个函数输入的例子:

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

和对应的输出:

{
  foo: 1,
  bar: 'hello'
}

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

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> }

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

  1. T一次只能取一个类型(上面的例子会在属性bar上抛出错误)
  2. return 类型具有未定义数量的键,而不是输入对象中存在的所有且唯一的键。

但我有点迷路了,真的不知道去哪里找,甚至不知道该去哪里找。

您可以尝试以下方法:

const conf = {
  foo: { value: 1, type: "number" },
  bar: { value: "hello", type: "string" }
};

type Input = {
  [key: string]: { value: any; type: string };
};

type Output<U extends Input> = { [Key in keyof U]: U[Key]["value"] };

function f<T extends Input>(input: T): Output<T> {
  // Details...
}

const returned = f(conf);

returned.foo // number
returned.bar // string

TypeScript playground

我认为这应该足够了.....关键是使用'any'

function change(x:any) {
  let y:any={};
  for(let c in x){
    console.log(c)
    y[c] = x[c].value;
  }
  return y;
}

let x={
  'foo': {value: 1, type: 'number'},
  'bar': {value: 'hello', type: 'string'}
};

console.log(change(x));

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

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

我假设您希望 "string" 映射到 string,然后我添加了 "object"。如果你想 "array" 映射到 string[] 你可以这样做,我想。

然后我想用TypeMap做一个联合类型Config代表valuetype之间的约束,像这样:

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

如果你检查它,它相当于:

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 中是泛型的,一个对象类型,其键是 whatever,其属性是 Config,由约束 Record<keyof T, Config> 表示。输入类型为T,输出类型maps每个属性 in T到其value 属性:

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

让我们看看它是否有效:

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

我认为这就是您期望的输出类型,对吧?如果您需要更窄的类型(例如,foo 类型 1 而不是 number),您可以使用 const assertion 在输入中:

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

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

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

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

Link to code