【问题标题】:Converting values in a dictionary to literal values将字典中的值转换为文字值
【发布时间】:2021-06-08 09:54:04
【问题描述】:

我知道您可能会很棘手,将传入字典中的 已知属性 转换为文字值。例如,对于带有“id”的字典,我们可以这样做:

function idLiteral<
  T extends { id: I }, 
  I extends PropertyKey
>(o: T): T & { id: T["id"] } {
  return { ...o, id: o.id };
}
// usage
const test = idLiteral({id: "abc", name: "Bobs your uncle" });

在这种情况下,name 将是 string 类型,但 id 将被分配为文字类型 abc。当然,在对象是静态的情况下,我们可以使用 Typescript as const 运算符将对象转换为狭义的文字类型,但我想知道我们是否可以使用通过函数传递的非静态字典来做到这一点。

我尝试过这样做:

function literalValues<T extends object>(obj: T): T extends { [K in keyof T]: Readonly<infer V> }[keyof T] 
  ? { [K in keyof T]: Readonly<V> } 
  : never {
  return obj;
}
// usage
const narrow = literalValues({foo: 1, bar: true});

希望narrow 变量会输出为{ foo: 1; bar: true }。遗憾的是,这并没有发生,而是出现了扩大的 { foo: number; bar: boolean } 类型。

然后我将注意力转向查看第一个函数——idLiteral——是否可能是可以泛化的东西,以便我通过迭代它来构建对象类型。我想出了这个:

export const literal = <T extends object, P extends keyof T>(obj: T) => (prop: P): T & { [P]: T[P] } => {
  return { ...obj, [prop]: obj[prop] };
};

const l = literal({ foo: 1, bar: true })("foo");

但此语法失败,因为P 不能用作对象的键。

这在 Typescript 中是可行的,还是我只是在浪费时间?感觉如此接近,但同时又如此遥远。

Playground Code

【问题讨论】:

    标签: typescript typescript-typings typescript-generics


    【解决方案1】:

    是的,这是 TypeScript 的痛点。不久前,我提交了microsoft/TypeScript#30680 请求一些简单的方法来注释通用函数签名以推断类型,就好像调用者使用了const assertion,而不需要调用者实际这样做。该功能请求仍然开放,但我不知道何时或是否会实施。

    目前,有一些技巧可以得到类似的行为,但对于外行来说,它们是神秘的。一种似乎相当一致的方法是使用两个泛型类型参数,一个对应于传入的实际值(称为T),另一个对应于您想要狭义推断的该类型的部分(调用它N)。然后你 constrain T 到相关类型,使用 N 表示其中包含文字的部分,并将 N 约束为包含 stringnumberboolean 的联合。像这样:

    type Narrowable = 
      string | number | boolean | symbol | object | undefined | void | null | {};
    
    function literalValues<N extends Narrowable, T extends Record<keyof T, N>>(
      obj: T
    ) {
      return obj;
    };
    

    当你调用它时,它会按照你想要的方式运行:

    const narrow = literalValues({ foo: 1, bar: true });
    /* const narrow: {
        foo: 1;
        bar: true;
    } */
    

    这有点奇怪,虽然T 现在被狭义地推断,N 不是:

    /* function literalValues<Narrowable, { foo: 1; bar: true; }> */  
    

    但你并不真正关心N,所以?‍♂️。

    如果您认为应该有一些不那么古怪的东西,我同意。如果您认为它特别引人注目,您可能想去 microsoft/TypeScript#30680 并给它一个 ? 和/或描述您的用例。

    Playground link to code

    【讨论】:

    • 你的超能力是惊人的......感谢上帝,你是 Stack Overflow 的贡献者。
    猜你喜欢
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    相关资源
    最近更新 更多