在TypeScript中作为参数传递时防止对象文本类型扩大

sqxo8psd  于 2022-12-19  发布在  TypeScript
关注(0)|答案(2)|浏览(204)

在最新的TypeScript版本中,有没有可能将一个对象文本作为参数传递给一个函数,而不需要扩展它,也不需要在调用中使用as const
TSPlayground链接:示例
我现在做的是:

function func<T>(value: T): T { 
    return value;
};

let test = func({ key: 'value' })
// type inferred as { key: string;}

我想要的是以下内容

// ... alternative declaration of func

let test = func({ key: 'value' })
// type inferred as { key: "value"; }

更准确地说,它应该适用于任何扩展Record<string,string>的对象文本
这些函数存档了我想要的结果,但是我不想改变调用函数的方式

function func<T>(value: T): T {
    return value
};

let test = func({ key: 'value' as const })
// type inferred as { key: "value"; }

let test = func({ key: 'value' } as const )
// type inferred as { readonly key: "value"; }

这可能吗?

eqoofvh9

eqoofvh91#

是的,这是可能的,但解决方案可能看起来不直观和多余。
你必须给函数添加另一个泛型类型。这将允许我们保留传递给函数的字符串常量的缩小类型。

function func<T extends Record<string, S>, S extends string>(value: T): T { 
    return value;
};

let test = func({ key: 'value', a: "a" })
// let test: {
//     key: "value";
//     a: "a";
// }

我们可以将此应用到您的复杂示例中。

declare function formatMessage<
  Key extends keyof typeof messages, 
  Props extends { [key: string]: S }, 
  S extends string
>(messageKey: Key, props?: Props)
    :ReplaceValues<(typeof messages)[Key],  NonNullable<typeof props>>;

let test4 = formatMessage("created", {name: "TestValue"})
// let test4: "TestValue was created successfully."

Playground
这里有一些更进一步的资源,帮助我解决了过去类似的问题。

c9qzyr3d

c9qzyr3d2#

对于其他人来说这个问题:ts-toolbelt有几个实用程序可以帮助处理这种类型混乱的情况,在这种情况下,F.narrow正是不使用任何技巧就可以推断出未加宽类型的工具:

import { F } from 'ts-toolbelt'

function func<T>(value: F.Narrow<T>) { 
    return value;
};

同样在TypeScript 5.0中出现的“const modifier“正是用于防止类型加宽的目的。

相关问题