gpt4 book ai didi

typescript - Typescript 中错误的自动返回类型推导

转载 作者:行者123 更新时间:2023-12-04 03:35:08 25 4
gpt4 key购买 nike

在设置类中,我有一个获取值的方法,如果找不到给定的键,则返回一个可选的默认值:

    /**
* Returns the value stored at the given key, which can have the form `qualifier.subKey`.
*
* @param key The key to look up.
* @param defaultValue An optional value to be returned if the there's no value at the given key or the key doesn't
* exist at all.
*
* @returns If a return value is given the return type is the same as that of the default value. Otherwise it's
* either undefined or the same as the type found at the given key.
*/
public get<T>(key: string, defaultValue: T): T;
public get(key: string): any;
public get<T>(key: string, defaultValue?: T): T | undefined {
const { target, subKey } = this.objectForKey(key, false);
if (!target || !subKey) {
return defaultValue;
}

return target[subKey] as T ?? defaultValue;
}

这个实现给了我意想不到的返回类型。考虑这个电话:

const removeIdleTime = settings.get("workers.removeIdleTime", 60);

变量removeIdleTime不是我期望的类型,而是类型 60 .我可以明确地使用 <number>作为 get 的模板/通用参数然后结果就可以了,但是让 Typescript 推断出正确的类型会更酷。必须改变什么才能实现这一目标?

更新

我刚找到关于 type widening 的描述在 Typescript 中(在写这个问题时我不知道正确的术语)。原来是在给get的结果赋值的时候加宽了类型到可变变量。否则它保持文字类型。

虽然这是一个有趣的信息,但它对解决这个问题没有帮助,因为 linters 通常会转换任何 letconst如果它们在初始分配后没有改变。

最佳答案

解决方案

感谢@Etheryte,我找到了一个解决方案:有一种方法可以通过使用条件类型来强制扩展类型。

export type ValueType<T> = T extends string
? string
: T extends number
? number
: T extends boolean
? boolean
: T extends undefined
? undefined
: [T] extends [any]
? T
: object;

可以这样使用(注意唯一的变化,返回类型):

    /**
* Returns the value stored at the given key, which can have the form `qualifier.subKey`.
*
* @param key The key to look up.
* @param defaultValue An optional value to be returned if the there's no value at the given key or the key doesn't
* exist at all.
*
* @returns If a return value is given the return type is the same as that of the default value. Otherwise it's
* either undefined or the same as the type found at the given key.
*/
public get<T>(key: string, defaultValue: T): ValueType<T>;
public get(key: string): any;
public get<T>(key: string, defaultValue?: T): T | undefined {
const { target, subKey } = this.objectForKey(key, false);
if (!target || !subKey) {
return defaultValue;
}

return target[subKey] as T ?? defaultValue;
}

这也适用于枚举,其中条件类型返回数字或字符串,具体取决于枚举的基本类型。


上一个答案

此行为是设计使然。分配给常量目标的文字值保持其文字类型。这遵循始终存储最窄类型的原则。在可以更改值的情况下(例如,通过将文字分配给可变变量),Typescript 转换器会扩大类型以允许除初始文字之外的其他值。您可以在文章 Literal Type Widening in TypeScript 中阅读更多相关信息.

没有办法(我知道)强制类型加宽,所以我在这里看到 3 种可能的方法:

  1. 分配 get 的结果时使用可变目标称呼。这可能会有问题,因为如果没有其他分配给它,linters 将尝试“优化”变量使其变得不可变。

  2. 向目标添加显式类型注释,例如:

const removeIdleTime: number = settings.get("workers.removeIdleTime", 60);

  1. 明确指定泛型参数:

const removeIdleTime = settings.get<number>("workers.removeIdleTime", 60);

const removeIdleTime = settings.get("workers.removeIdleTime", 60 as number);

不过,所有这些方法都不能真正解决我的问题。

关于typescript - Typescript 中错误的自动返回类型推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67057855/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com