【问题标题】:Preventing object literals type widening when passed as argument in TypeScript在 TypeScript 中作为参数传递时防止对象文字类型扩大
【发布时间】:2022-12-14 23:37:07
【问题描述】:

在最新的 TypeScript 版本中,是否可以将对象文字作为参数传递给函数而不扩展它,并且在调用中也不使用 as const

TS游乐场链接:Example

我目前所做的是:

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&lt;string,string&gt; 的对象文字

这些存档我想要的结果,但我不想改变必须调用函数的方式

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

这可能吗?

【问题讨论】:

  • github.com/Microsoft/TypeScript/pull/10676 似乎在谈论这个:“为对象文字中的属性推断的类型是表达式的扩展文字类型,除非该属性具有包含文字类型的上下文类型。”但是我不太明白在我的情况下如何使“上下文类型包括文字类型”,或者这到底意味着什么

标签: typescript generics arguments type-inference object-literal


【解决方案1】:

是的,这是可能的。但该解决方案可能看起来不直观且多余。

您将必须向该函数添加另一个泛型类型。这将允许我们保留传递给函数的字符串文字的缩小类型。

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


这里有一些进一步的资源,它们帮助我解决了过去的这些问题。

【讨论】:

  • 非常感谢,这正是我要找的。我做对了吗,使参数对象的值成为通用的以及以某种方式标记上下文类型以包含 PR 中提到的文字类型?从而使其保持狭窄。
  • 是的,我怀疑这几乎就是这里发生的事情。
【解决方案2】:

对于遇到这个问题的其他人:ts-toolbelt 有几个实用程序可以帮助处理这种类型的杂耍。在这种情况下,F.narrow 正是在不使用某种技巧的情况下推断出类型所需要的:

import { F } from 'ts-toolbelt'

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

同样出现在 TypeScript 5.0 中的“const modifier”正是为了防止类型扩大这一目的。

【讨论】:

    猜你喜欢
    • 2019-12-21
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多