Microsoft/TypeScript

Narrowing empty string or false in generic misbehaves

Open

#58,232 创建于 2024年4月17日

在 GitHub 查看
 (2 评论) (0 反应) (0 负责人)TypeScript (6,726 fork)batch import
Domain: check: Control FlowHelp WantedPossible Improvement

仓库指标

Star
 (48,455 star)
PR 合并指标
 (平均合并 6天 17小时) (30 天内合并 9 个 PR)

描述

🔎 Search Terms

generic, narrowing, empty string, false, falsy

🕗 Version & Regression Information

This is the behavior in every version I tried, but it seems to behave a little worse with TS v4.2.3 and prior.

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.5.0-dev.20240417#code/GYVwdgxgLglg9mABKSBGAPAFUQUwB5Q5gAmAzomCALYBGOATogD4UgA2bzi4xOwMYHMS7AAhm1I4uAcmkA+ABR4AXK1oMumAJSIA3gCgAkPRxQQ9JHmYsefAUIDc+gL76U0eEncAmLLgJEZGp0jCyUHFy2-ILCLGISUiyyiirBGizaekYmZhaIVgD8+YhyiAAMiEVWqgC01flOru6wCMjgEADMfviEJOSU6qGsETYkdjEi4pIy8kqqAyGaOgbGpuaWlYgAsqJQABYAdKI0pEo6qniN+voQCKRQ+fPUi6O80UKIALxtaAqyWk5bmB7ogAJ5fH4QbwKGodAE3O4PABeEPcHRhcIcQA

💻 Code

function func1<T extends number | null | undefined | false | ''>(x: number | T) {
	return x || undefined;
}
function func2<T extends number | null | undefined | false | ''>(x: number | T) {
	return x ? x > 0 ? x : -x : x;
}
function func3<T extends number | null | undefined | false | ''>(x: number | T) {
	return x ? Math.abs(x) : x;
}

const x: number | undefined = func1('');
const y = func2(-3);
const z = func3(-3);

🙁 Actual behavior

The inferred return type of func1 can contain false or '' depending on T. It's wrong because x || undefined can never result in false or '' and thus should not be in the resulting type.

func2 fails type checking: Operator '>' cannot be applied to types 'number | NonNullable<T>' and 'number'.. It's wrong because the truthiness check should narrow x to number. (Note that func3 succeeds type checking because the signature of Math.abs seems to provide supplemental information which narrows x to number.)

🙂 Expected behavior

The inferred return type of func1 is should number | undefined, regardless of T.

func2 is expected to pass type checking, x having been narrowed to number with the truthiness check.

Additional information about the issue

All functions act 'correctly' if defined without the use of generics, but it's inadequate because the return type of func2 and func3 would always be number | null | undefined | false | '' regardless of argument type.

My actual use case is creating functions that transform numeric inputs and propagate falsy values. I've worked around this issue using type assertions in spots where narrowing misbehaves.

贡献者指南