【问题标题】:Typescript `could be instantiated with a different subtype of constraint` error打字稿`可以用不同的约束子类型实例化`错误
【发布时间】:2021-08-14 18:26:04
【问题描述】:

当我返回的结果应该符合函数的预期类型时,我不断收到could be instantiated with a different subtype of constraint 错误,我无法理解我做错了什么。这是我的代码,删除了所有不相关的细节:

type User = { }

interface BasePageProps {
    user: User
}

type GetServerSidePropsResult<P> =
  | { props: P }

type PropsWithUser = <TProps extends BasePageProps>(
    callback: (user: User) => Promise<Omit<TProps, 'user'>>
) => Promise<GetServerSidePropsResult<TProps>>

export const testFunc: PropsWithUser = async (callback) => {
    const user = {}
    return { props: {
            user,
            ...(await callback(user))
        } }
}

这是我得到的错误:

'{ 用户:{}; } & Omit' 可分配给类型为“TProps”的约束,但可以使用约束“BasePageProps”的不同子类型来实例化“TProps”。

Here's this example on TS Playground.

为什么用不同子类型实例化的潜在TProps 是个问题?我该如何解决?

P.S.:您可能会注意到这些类型取自 Next.js。不过这个问题跟 Next.js 本身没有关系,所以请不要给这个问题打标签。

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    你的函数的有效签名是:

    type PropsWithUser = <TProps extends BasePageProps>(
        callback: (user: User) => Promise<Omit<TProps, 'user'>>
    ) => Promise<GetServerSidePropsResult<BasePageProps & Omit<TProps, 'user'>>>
    

    或者你可以删除一些重复:

    type PropsWithUser = <TProps extends BasePageProps, TO = Omit<TProps, 'user'>(
        callback: (user: User) => Promise<TO>
    ) => Promise<GetServerSidePropsResult<BasePageProps & TO>>
    

    证明编译器正确引发代码错误的反例。让我们定义一个扩展 BasePageProps 但不通过函数结果类型检查的 TProps 类型的具体示例:

    type User = { }
    
    type AnotherUser = { a: string }
    
    interface TProps {
        user: AnotherUser
    }
    
    interface BasePageProps {
        user: User
    }
    
    type Eq = TProps extends BasePageProps ? true : false // type Eq = true
    
    type PropsWithUser = <TProps extends BasePageProps>(
        callback: (user: User) => Promise<Omit<TProps, 'user'>>
    ) => Promise<GetServerSidePropsResult<TProps>>
    

    TS playground

    所以你的函数应该返回类型为Promise&lt;{ props: { user: AnotherUser, ... } }&gt; 的结果。它显然没有。

    正如错误所说:'{ user: {}; } &amp; Omit&lt;TProps, "user"&gt;' is assignable to the constraint of type 'TProps', but 'TProps' could be instantiated with a different subtype of constraint 'BasePageProps'

    type User = { }
    
    interface BasePageProps {
        user: User
    }
    
    type AnotherUser = { a: string }
    
    interface ConcreteTProps {
        user: AnotherUser
    }
    
    // { user: {}; } & Omit<TProps, "user"> is assignable
    // to the constraint of type TProps (i.e. BasePageProps)
    const a: BasePageProps = { user: {} }
    
    // but 'TProps' could be instantiated with a different 
    // subtype of constraint 'BasePageProps' (i.e. ConcreteTProps)
    // Which is a subtype of BasePageProps by cannot be 
    // assigned with { user: User }
    const b: ConcreteTProps = { user: {} } // error
    

    【讨论】:

    • 没想到字段的类型也可以在扩展接口上扩展,谢谢!
    猜你喜欢
    • 2020-01-22
    • 2020-05-30
    • 2021-11-24
    • 2021-06-26
    • 2022-01-20
    • 2021-02-13
    • 2020-03-27
    • 2019-12-13
    • 1970-01-01
    相关资源
    最近更新 更多