打字稿:在没有实际扩展/扩大的情况下捕获/推断类型的约束

Posted

技术标签:

【中文标题】打字稿:在没有实际扩展/扩大的情况下捕获/推断类型的约束【英文标题】:Typescript: capture/infer type with constraint without actually extending/widening 【发布时间】:2022-01-23 06:28:16 【问题描述】:

我有一个函数build,它使用传入的参数构建一个User。我想键入函数,以便它知道传入了哪些参数并在返回值中考虑它们。

我的第一个想法是捕获params 的类型并在返回类型中使用它:

type User =  name: string; admin: boolean ;

const build = <T extends User>(params: T): T => params

效果很好,我现在可以这样做:

build( name: 'Jan', admin: true );
// return type is:  name: string, admin: true  as desired (notice admin: true, not boolean)

但是,使用&lt;T extends User&gt; 约束来捕获类型似乎会产生意想不到的结果,即也会扩大类型。现在允许以下内容没有错误:

build( name: 'Jan', admin: true, foo: 'shouldnt be allowed' );
// return type is:  name: string, admin: true, foo: string 

如果我采用一种更简单的方法,即不捕获类型而只返回User,我会得到所需/预期的行为,其中传递User 上不存在的参数会导致错误,但该函数返回一个User,而没有来自参数的额外类型信息:

const build = (params: User): User => params

// Type error as desired: Object literal may only specify known 
// properties, and 'foo' does not exist in type 'User'
build( name: 'Jan', admin: true, foo: 'sdf' )

我想知道是否有一种方法可以捕获params 的类型,以便我可以在返回类型中使用它,但不会扩大类型。

【问题讨论】:

您的要求不明确。你希望它接受User 的子类型吗?如果是,第一种方法是正确的。您需要在调用它时明确定义泛型。如果不是,则第二种方法是正确的, 术语和语义说明:额外的属性不会加宽类型,它们会缩小类型。像inferface A a: string 这样的类型意味着“任何对象,只要它在键a 处具有string-valued 属性”。这就是结构类型和接口可扩展性的工作原理:对于interface B extends A b: number,每个B 也是一个A。而且BA,因为不是每个A 也是B 【参考方案1】:

Typescript 没有实现exact types,但您可以对参数类型创建自定义限制。例如(playground):

type User =  name: string; admin: boolean ;

const build = <T extends User>(
    params: keyof T extends keyof User ? T : never
): T => params

// const user1:  name: string; admin: true; 
const user1 = build( name: 'Jan', admin: true, );

// ERROR
const user2 = build( name: 'Jan', admin: true, x: 1);

同样的想法,更冗长,但更好的错误处理:

const build = <T extends User>(
    params: keyof T extends keyof User ? T : User
): Pick<T, keyof User> => params

【讨论】:

谢谢!这非常适合我的情况。为了更好地处理错误,我选择了更详细的版本。

以上是关于打字稿:在没有实际扩展/扩大的情况下捕获/推断类型的约束的主要内容,如果未能解决你的问题,请参考以下文章

打字稿推断出不正确的类型:TS2339 属性“选定”在类型“字符串”上不存在

打字稿不推断通用对象的值

打字稿:在对象内推断通用对象的类型

文字类型推断 - 打字稿

如何在打字稿中没有运行时副作用的情况下进行精确的类型检查?

打字稿泛型:从函数参数的类型推断类型?