Typescript 如何修复TS2322:“;可以使用约束的不同子类型';对象'&引用;?

Typescript 如何修复TS2322:“;可以使用约束的不同子类型';对象'&引用;?,typescript,typescript-generics,Typescript,Typescript Generics,在递归类型中存在类型检查错误 我正在尝试为react jss styles对象编写类型 类型样式fn=( 道具:P )=>CSS.Properties | number |字符串; 类型JssValue= |串 |数 |排列 |StylesFn; //@ts忽略 接口样式对象 扩展样式{ [x:string]:CSS.Properties | style; } 导出类型样式={ [x in K]:CSS.Properties|StylesObject|StylesFn }; 它工作正常,但ty

在递归类型中存在类型检查错误

我正在尝试为react jss styles对象编写类型

类型样式fn=(
道具:P
)=>CSS.Properties | number |字符串;
类型JssValue

= |串 |数 |排列 |StylesFn

; //@ts忽略 接口样式对象 扩展样式{ [x:string]:CSS.Properties | style; } 导出类型样式={ [x in K]:CSS.Properties|StylesObject|StylesFn

};

它工作正常,但typescript写入错误。我使用了
@ts ignore
,但这并不奇怪

错误24:11 typecheck接口“StylesObject”错误地扩展了接口“Styles”。
索引签名不兼容。
类型“Properties | Styles”不可分配给类型“StylesFn | Properties | StylesObject”。
类型“Properties”不可分配给类型“StylesFn | Properties | StylesObject”。
类型“Properties”不可分配给类型“Properties”。
类型“JssValue

”不可分配给类型“JssValue”。 类型“StylesFn

”不可分配给类型“JssValue”。 类型“StylesFn

”不可分配给类型“StylesFn”。 类型“{}”不可分配给类型“P”。 “{}”可分配给“P”类型的约束,但“P”可以用约束“object”的不同子类型实例化。


这个错误是什么意思?

这个错误是在警告您,您的泛型类型
p
不能分配给
{}
,因为泛型类型
p
可以是一个更明确的定义,或者限制为一个可能与默认值冲突的特定类型

这意味着值
{}
不能满足泛型类型
p
可以使用的所有可能类型

让我们创建另一个只包含布尔值的示例,该示例应该更容易理解:

interface OnlyBoolIdentityInterface<T> {
  (arg: T): T;
}

function onlyBoolGeneric<T extends boolean>(arg: T = false): T {
  return arg;
}
如果专门使用函数
OnlyBoolIdentityInterface
,只支持这样的真值:

const onlyTrueIdentity: OnlyBoolIdentityInterface<TrueType> = onlyBoolGeneric;
const onlyTrueIdentity:OnlyBoolIdentityInterface=onlyBoolGeneric;
即使TrueType遵守由
T extends boolean
设置的约束,默认值
arg:T=false
也不是
TrueType

这就是错误试图传达给你的情况

那么,如何修复这类错误呢

  • 或者删除默认值
  • 或者T需要扩展缺省参数的特殊类型,在我的示例中,缺省参数为false
  • 或T可以直接干扰接收默认参数的参数

  • 有关此错误消息的更多内容,请参阅建议此错误消息的问题。

    补充@fetzz的精彩答案


    简短回答 TLDR此类错误消息有两种常见原因。你正在做第一个(见下文)。除了文本之外,我还详细解释了这个错误消息想要传达什么

    原因1:在typescript中,不允许将具体实例分配给类型参数。下面您可以看到“问题”和“问题已解决”的示例,这样您就可以比较两者的差异并查看有哪些变化:

    问题

    const func1=

    原因2:尽管您没有在代码中执行以下错误。这也是出现此类错误消息的正常情况。您应该避免这样做:

    在类、类型或接口中重复(错误地)类型参数

    不要让下面代码的复杂性迷惑您,我希望您关注的唯一一件事是删除字母“A”如何解决问题:

    问题:

    输入Foo


    长答案
    了解错误消息 下面,我将分解以下错误消息的每个元素:

    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或未定义之外的任何内容。例如:

    type TrueType = true;
    
    类型A={}
    常数a0:A=未定义//错误
    常数a1:A=null//错误
    常数a2:A=2//ok
    常量a3:A=‘你好,世界’//好的
    常量a4:A={foo:'bar'}//ok
    //等等。。。
    
    见:


    什么是
    是不可分配的
    赋值就是使特定类型的变量对应于特定实例。如果实例的类型不匹配,则会出现错误。例如:

    type TrueType = true;
    
    //类型字符串不能分配给类型编号
    常量a:number='hello world'//错误
    //类型编号与类型编号相同
    常数b:number=2//ok
    

    什么是
    不同的子类型
    两种类型是相等的:如果它们不添加或删除彼此相关的详细信息

    两种类型是不同的:如果它们不相等

    类型
    A
    是类型
    S
    的一个子类型:如果
    A
    添加细节而不删除
    S
    中已经存在的细节

    类型
    A
    和类型
    B
    是类型
    S
    的不同子类型:如果
    A
    B
    S
    的子类型,但是
    A
    B
    是不同的类型。换句话说:
    A
    B
    为类型
    S
    添加了细节,但它们没有添加相同的细节

    示例:在下面的代码中,以下所有语句均为true:

  • A和D是相等的类型
  • B是A的亚型
  • E不是A的子类型
  • B和C是A的不同亚型
  • type A={readonly 0:'0'}
    类型B={readonly 0:'0',readonly foo:'foo'}
    类型C={readonly 0:'0',readonly bar:'bar'}
    类型D={readonly 0:'0'}
    类型E={readonly 1:'
    
    type ObjectWithPropType<T> = {prop: T};
    
    // Mind return type - T
    const createCustomObject = <T extends ObjectWithPropType<any>>(prop: any): T => ({ prop });
    
    type CustomObj = ObjectWithProp<string> & { id: string };
    
    const customObj = createCustomObj<CustomObj>('value'); // Invalid
    // function will only ever return {prop: T} type.
    
    type StringPropObject = ObjectWithPropType<string>
    
    const createCustomObject = <T>(prop: T extends ObjectWithPropType<infer U> ? U : T): ObjectWithPropType<T> => ({ prop });
    
    const stringObj = createCustomObject<StringPropObject>('test');