CSS.Properties> | num-6ren">
gpt4 book ai didi

typescript - 如何修复 TS2322 : "could be instantiated with a different subtype of constraint ' object'"?

转载 作者:搜寻专家 更新时间:2023-10-30 20:32:13 27 4
gpt4 key购买 nike

A 在递归类型中存在类型检查错误。
我正在尝试为 react-jss 样式对象编写类型。

type StylesFn<P extends object> = (
props: P
) => CSS.Properties<JssValue<P>> | number | string;

type JssValue<P extends object> =
| string
| number
| Array<string | number>
| StylesFn<P>;

// @ts-ignore
interface StylesObject<K extends string = any, P extends object = {}>
extends Styles {
[x: string]: CSS.Properties<JssValue<P>> | Styles<K, P>;
}
export type Styles<K extends string = any, P extends object = {}> = {
[x in K]: CSS.Properties<JssValue<P>> | StylesObject<any, P> | StylesFn<P>
};
它工作正常,但 typescript 写了一个错误。我用 @ts-ignore ,但这并不花哨
ERROR 24:11  typecheck  Interface 'StylesObject<K, P>' incorrectly extends interface 'Styles<any, {}>'.
Index signatures are incompatible.
Type 'Properties<JssValue<P>> | Styles<K, P>' is not assignable to type 'StylesFn<{}> | Properties<JssValue<{}>> | StylesObject<any, {}>'.
Type 'Properties<JssValue<P>>' is not assignable to type 'StylesFn<{}> | Properties<JssValue<{}>> | StylesObject<any, {}>'.
Type 'Properties<JssValue<P>>' is not assignable to type 'Properties<JssValue<{}>>'.
Type 'JssValue<P>' is not assignable to type 'JssValue<{}>'.
Type 'StylesFn<P>' is not assignable to type 'JssValue<{}>'.
Type 'StylesFn<P>' is not assignable to type 'StylesFn<{}>'.
Type '{}' is not assignable to type 'P'.
'{}' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'object'.
这个错误是什么意思?

最佳答案

补充@fetzz 很好的答案。

简答
TLDR; 此类错误消息有两个常见原因。你正在做第一个(见下文)。与文本一起,我详细解释了此错误消息想要传达的内容。
原因 1:在 typescript 中,不允许将具体实例分配给类型参数。下面你可以看到一个“问题”和“问题解决”的例子,这样你就可以比较差异,看看有什么变化:
问题

const func1 = <A extends string>(a: A = 'foo') => `hello!` // Error!

const func2 = <A extends string>(a: A) => {
//stuff
a = `foo` // Error!
//stuff
}
解决方案
const func1 = <A extends string>(a: A) => `hello!` // ok

const func2 = <A extends string>(a: A) => { //ok
//stuff
//stuff
}
见: TS Playground
原因 2:尽管您没有在代码中执行以下错误。出现这种错误信息也是正常情况。你应该避免这样做:
重复(错误地) Type Parameter在类、类型或接口(interface)中。
不要让下面代码的复杂性使您感到困惑,我唯一希望您关注的是删除字母“A”如何解决问题:
问题:
type Foo<A> = {
//look the above 'A' is conflicting with the below 'A'
map: <A,B>(f: (_: A) => B) => Foo<B>
}

const makeFoo = <A>(a: A): Foo<A> => ({
map: f => makeFoo(f(a)) //error!
})
解决方案:
type Foo<A> = {
// conflict removed
map: <B>(f: (_: A) => B) => Foo<B>
}

const makeFoo = <A>(a: A): Foo<A> => ({
map: f => makeFoo(f(a)) //ok
})
见: TS Playground

长答案

了解错误信息
下面我将分解错误消息的每个元素:
Type '{}' is not assignable to type 'P'.
'{}' is assignable to the constraint of type 'P', but 'P' could be
instantiated with a different subtype of constraint'object'

什么是类型 {}
这是一种您可以分配除 null 或 undefined 之外的任何内容的类型。例如:
type A = {}
const a0: A = undefined // error
const a1: A = null // error
const a2: A = 2 // ok
const a3: A = 'hello world' //ok
const a4: A = { foo: 'bar' } //ok
// and so on...
见: TS Playground

什么是is not assignable
赋值就是让一个特定类型的变量对应一个特定的实例。如果实例类型不匹配,则会出现错误。例如:
// type string is not assignable to type number 
const a: number = 'hello world' //error

// type number is assinable to type number
const b: number = 2 // ok


什么是different subtype
两种类型相等 :如果他们不添加或删除彼此相关的详细信息。
两种类型不同 : 如果他们不相等。
类型 A是类型 S 的子类型 : 如果 A添加详细信息而不从 S 中删除已存在的详细信息.
类型 A并输入 B是类型 S 的不同子类型 : 如果 ABS 的子类型,但是 AB是不同的类型。换句话说: AB为类型添加细节 S ,但它们没有添加相同的细节。
示例:在下面的代码中,以下所有语句都为真:
  • A 和 D 是相等类型
  • B 是 A 的亚型
  • E 不是 A 的亚型
  • B和C是A的不同亚型

  • type A = { readonly 0: '0'}
    type B = { readonly 0: '0', readonly foo: 'foo'}
    type C = { readonly 0: '0', readonly bar: 'bar'}
    type D = { readonly 0: '0'}
    type E = { readonly 1: '1', readonly bar: 'bar'}
    type A = number
    type B = 2
    type C = 7
    type D = number
    type E = `hello world`
    type A = boolean
    type B = true
    type C = false
    type D = boolean
    type E = number

    NOTE: Structural Type

    When you see in TS the use of type keyword, for instance in type A = { foo: 'Bar' } you should read: Type alias A is pointing to type structure { foo: 'Bar' }.

    The general syntax is: type [type_alias_name] = [type_structure].

    Typescript type system just checks against [type_structure] and not against the [type_alias_name]. That means that in TS there's no difference in terms of type checking between following: type A = { foo: 'bar } and type B = { foo: 'bar' }. For more see: Official Doc.



    什么是 constraint of type 'X'
    类型约束只是您放在“扩展”关键字右侧的内容。在下面的例子中, Type Constraint是'B'。
    const func = <A extends B>(a: A) => `hello!`
    阅读:类型约束“B”是 constraint of type 'A'
    为什么会发生错误
    为了说明,我将向您展示三个案例。在每种情况下唯一会有所不同的是 Type Constraint ,其他都不会改变。
    我想让你注意的是 Type Constraint 的限制施加到 Type Parameter不包括不同的亚型。让我们看看:
    鉴于:
    type Foo         =  { readonly 0: '0'}
    type SubType = { readonly 0: '0', readonly a: 'a'}
    type DiffSubType = { readonly 0: '0', readonly b: 'b'}

    const foo: Foo = { 0: '0'}
    const foo_SubType: SubType = { 0: '0', a: 'a' }
    const foo_DiffSubType: DiffSubType = { 0: '0', b: 'b' }
    案例1: 无限制
    const func = <A>(a: A) => `hello!`

    // call examples
    const c0 = func(undefined) // ok
    const c1 = func(null) // ok
    const c2 = func(() => undefined) // ok
    const c3 = func(10) // ok
    const c4 = func(`hi`) // ok
    const c5 = func({}) //ok
    const c6 = func(foo) // ok
    const c7 = func(foo_SubType) //ok
    const c8 = func(foo_DiffSubType) //ok

    案例2: 一些限制
    请注意下面的限制不会影响子类型。

    VERY IMPORTANT: In Typescript the Type Constraint does not restrict different subtypes


    const func = <A extends Foo>(a: A) => `hello!`

    // call examples
    const c0 = func(undefined) // error
    const c1 = func(null) // error
    const c2 = func(() => undefined) // error
    const c3 = func(10) // error
    const c4 = func(`hi`) // error
    const c5 = func({}) // error
    const c6 = func(foo) // ok
    const c7 = func(foo_SubType) // ok <-- Allowed
    const c8 = func(foo_DiffSubType) // ok <-- Allowed
    案例3: 更多约束
    const func = <A extends SubType>(a: A) => `hello!`

    // call examples
    const c0 = func(undefined) // error
    const c1 = func(null) // error
    const c2 = func(() => undefined) // error
    const c3 = func(10) // error
    const c4 = func(`hi`) // error
    const c5 = func({}) // error
    const c6 = func(foo) // error <-- Restricted now
    const c7 = func(foo_SubType) // ok <-- Still allowed
    const c8 = func(foo_DiffSubType) // error <-- NO MORE ALLOWED !

    TS playground

    结论
    功能如下:
    const func = <A extends Foo>(a: A = foo_SubType) => `hello!` //error!
    产生此错误消息:
    Type 'SubType' is not assignable to type 'A'.
    'SubType' is assignable to the constraint of type 'A', but 'A'
    could be instantiated with a different subtype of constraint
    'Foo'.ts(2322)
    因为 Typescript 推断 A从函数调用开始,但语言中没有限制您使用不同的“Foo”子类型调用函数。例如,下面的所有函数调用都被认为是有效的:
    const c0 = func(foo)  // ok! type 'Foo' will be infered and assigned to 'A'
    const c1 = func(foo_SubType) // ok! type 'SubType' will be infered
    const c2 = func(foo_DiffSubType) // ok! type 'DiffSubType' will be infered
    因此,将具体类型分配给泛型 Type Parameter不正确,因为在 TS 中 Type Parameter总是可以实例化为一些任意不同的子类型。
    解决方法:
    永远不要将具体类型分配给泛型类型参数,将其视为 read-only !相反,请执行以下操作:
    const func = <A extends Foo>(a: A) => `hello!` //ok!
    TS Playground

    关于typescript - 如何修复 TS2322 : "could be instantiated with a different subtype of constraint ' object'"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56505560/

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