Typescript:扩展字符串文字联合类型中的必需值

Typescript:扩展字符串文字联合类型中的必需值,typescript,Typescript,(目前使用的是Typescript 4.3) 假设我定义了以下联合类型以及一些泛型函数 types.ts export type Foo = 'a' | 'b' | 'c' export function Function<F extends Foo>() { ... } types.ts 导出类型Foo='a'|'b'|'c' 导出函数函数(){…} 我想做的是以某种方式使函数的任何通用用法都应该包含类型“a”(即,扩展Foo的任何F都必须包含“a”) 在代码中,我想要的是

(目前使用的是Typescript 4.3) 假设我定义了以下联合类型以及一些泛型函数

types.ts

export type Foo = 'a' | 'b' | 'c'

export function Function<F extends Foo>() { ... }
types.ts
导出类型Foo='a'|'b'|'c'
导出函数函数(){…}
我想做的是以某种方式使函数的任何通用用法都应该包含类型“a”(即,扩展Foo的任何F都必须包含“a”)

在代码中,我想要的是:

Function<'a' | 'b'>() // succeeds
Function<'c'>() // fails
Function<'a'>() // succeeds
Function()//成功
函数()//失败
函数()//成功

有什么方法可以修改Foo或Function的类型定义来实现这一点吗?

一般来说,已声明但未使用的类型参数是。此外,已经有一个名为
Function
的全局对象,您可能不想对其进行阴影处理。为了更易于分析,我将修改您的示例:

type Foo = 'a' | 'b' | 'c';

function func<F extends Foo>(f: F) { return f; } 
// function func<F extends Foo>(f: F): F
但这很少比让编译器推断更好:

const y = func(Math.random() < 0.5 ? "a" : "b");
// const y: "a" | "b"
以下几点应该失败:

func(Math.random() < 0.5 ? "a" : "d"); // fails
func("c") // should fail but doesn't
这可能很难理解,但它同时强制执行
F extends Foo
“a”扩展F
(后者是表示
F super“a”
)的另一种方式)。它的行为符合您的要求:

func(Math.random() < 0.5 ? "a" : "b"); // okay
func("a") // okay
func("c") // fails
现在,
“a”
不再可能不扩展
F
,因为
F
只是我们给
G
“a”
联合的一个名称。当然,由于您正在更改类型参数的定义,它将相应地更改推理和IntelliSense显示:

func(Math.random() < 0.5 ? "a" : "b"); // okay
// function func3<"b">(f: "a" | "b"): "a" | "b"

func("a") // okay
// function func<"a">(f: "a"): "a"

func(Math.random() < 0.5 ? "a" : "d"); // fails

func("c") // okay!
// function func<"c"> (f: "a" | "c"): "a" | "c"
func(Math.random()<0.5?“a”:“b”);//可以
//函数func3(f:“a”|“b”):“a”|“b”
func(“a”)//好的
//函数func(f:“a”):“a”
func(Math.random()<0.5?“a”:“d”);//失败
func(“c”)//好的!
//函数func(f:“a”|“c”):“a”|“c”
最后一次调用没有失败,因为值
“c”
的类型是
“a”|“c”
。这种类型的调用失败是否重要可能会影响您是否可以走这条路线。但对于某些用例,这可能比显式的下限模拟更好

function func<F extends ("a" extends F ? Foo : "a")>(f: F) { return f; }
// function func<F extends "a" extends F ? Foo : "a">(f: F): F
func(Math.random() < 0.5 ? "a" : "b"); // okay
func("a") // okay
func("c") // fails
function func<G extends Foo>(f: G | "a") { return f; }
// function func<G extends Foo>(f: G | "a"): G | "a"
func(Math.random() < 0.5 ? "a" : "b"); // okay
// function func3<"b">(f: "a" | "b"): "a" | "b"

func("a") // okay
// function func<"a">(f: "a"): "a"

func(Math.random() < 0.5 ? "a" : "d"); // fails

func("c") // okay!
// function func<"c"> (f: "a" | "c"): "a" | "c"