2322:可分配给类型"T"的约束,但"T"可以使用不同的约束子类型实例化



有人知道addChildrenDefaultValue工作但addChildrenDefaultValue2抛出的原因吗

Type '(Omit<T, "children"> & { children: ObjectWithChildren<TestObject>[]; })[]' is not assignable to type 'ObjectWithChildren<T>[]'.
Type 'Omit<T, "children"> & { children: ObjectWithChildren<TestObject>[]; }' is not assignable to type 'ObjectWithChildren<T>'.
Type 'Omit<T, "children"> & { children: ObjectWithChildren<TestObject>[]; }' is not assignable to type 'T'.
'Omit<T, "children"> & { children: ObjectWithChildren<TestObject>[]; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'TestObject'.(2322)

有更好的方法吗?(我正在使用extends,因为在我的用例中它扩展了更多类型(


interface TestObject{
name: string;
children?: TestObject[] | null;
}
type ObjectWithChildren<T> = T & {children: ObjectWithChildren<T>[]};
function addChildrenDefaultValue(
taxonomy: TestObject[]
): ObjectWithChildren<TestObject>[] {
return taxonomy.map(({children, ...props}) => {
return {...props, children: addChildrenDefaultValue(children ?? [])};
});
}
function addChildrenDefaultValue2<T extends TestObject>(
taxonomy: T[]
): ObjectWithChildren<T>[] {
return taxonomy.map(({children, ...props}) => {
return {...props, children: addChildrenDefaultValue2(children ?? [])};
});
}

它抛出错误的原因有两个。

  1. 因为您的接口引用了自己,所以类型T有类型为TestObject[]的子级,而不是您可能想要的类型T[]。这使得类型可能不兼容(T可以是很多东西,但TestObject不能(。

  2. 以这种方式使用map(使用排列,然后重新定义属性(是省略子项,然后使用非可选定义重新添加它。所以递归类型的类型需要反映这一点。

type TestObject<TChild> = {
name: string;
children?: TChild[] | null;
}
type ObjectWithChildren<T extends TestObject<T>> = Omit<T, "children"> & 
{children: ObjectWithChildren<T>[]};
function addChildrenDefaultValue2<T extends TestObject<T>>(
taxonomy: T[]
): ObjectWithChildren<T>[] {
return taxonomy.map(({children, ...props}) => {
return {...props, children: addChildrenDefaultValue2<T>(children ?? [])};
});
}

考虑以下类型的

type TestObjectExtended = TestObject & {
age: number
}

TestObjectExtendedchildren属性的类型为TestObject[] | null | undefined。因此,在函数addChildrenDefaultValue2中,T的属性children将具有相同的类型-TestObject[] | null | undefined

现在,在map函数的回调/映射器中,children的类型是TestObject[] | null | undefined,而不是T[] | null | undefined。在addChildrenDefaultValue2的递归调用中,子函数必然不满足函数的约束,因为它是TestObject[](如果不是undefined/null(,但期望是T[]

QED

最新更新