类型"ScopeType<T,未知>"不能分配给TypeScript中的类型"ParentScopeType<S>"?



在我的大型编译器项目中,我将错误代码隔离为:

type UserType = {
email: string
}
type ScopeType<S, P extends unknown = unknown> = {
data: S
parent?: P extends ScopeType<infer T, infer Q>
? ScopeType<T, Q>
: never
}
type PossibleScopeType<ST> = ST extends ScopeType<
infer S,
infer P
>
? ST | (P extends ScopeType<infer A, infer B> ? (P | PossibleScopeType<P>) : never)
: never
type ModuleType = {
path: string
}
const scope: ScopeType<ModuleType> = {
data: {
path: './foo.x',
},
}
const scope2: ScopeType<UserType, ScopeType<ModuleType>> = {
data: {
email: 'foo@bar.com',
},
parent: scope,
}
let scope3: PossibleScopeType<typeof scope2> = scope
scope3 = scope
let scope4: PossibleScopeType<ScopeType<UserType, ScopeType<ModuleType>>> = scope
scope3 = scope
export type ParentScopeType<S> =
// | S
S extends ScopeType<infer X, infer Y> ? S : S
function test<T, S extends ScopeType<T>>(scope: S): void {
let source: ParentScopeType<S> | undefined = scope
console.log(source)
}
test<UserType, ScopeType<UserType>>(scope2)

在下面的函数test中,这一行在source抛出错误:

let source: ParentScopeType<S> | undefined = scope

它说:

Type 'S' is not assignable to type 'ParentScopeType<S> | undefined'.
Type 'ScopeType<T, unknown>' is not assignable to type 'ParentScopeType<S>'.(2322)

我为此挣扎了几个小时。在这种情况下,我只是在调试,在ParentScopeType中,我只是在两个条件分支中返回S(ScopeType) !如果我注释掉条件分支,只输入以下内容,它就会编译:

type ParentScopeType<S> = S

相同
function test<T, S extends ScopeType<T>>(scope: S): void {
let source: S | undefined = scope
console.log(source)
}

我不明白为什么条件分支完全改变了逻辑,因为它在两个分支中都返回S…这里有些可疑之处,我对条件类型如何工作的理解一定是错误的。你能告诉我如何保持函数test原样,并让它编译吗?ParentScopeType应该是当前作用域及其所有父类(如Scope1 | Scope1Parent | Scope1ParentParent | ...)的类型。

这是另一个轻微的变化,同样的错误。

一个更原始的例子是:

type ParentType<S> = S extends object ? string : number
function test2<T>(scope: T): void {
let source: ParentType<T> | undefined = 'hello'
console.log(source)
}

我得到错误:

Type 'string' is not assignable to type 'ParentType<T>'

为什么它不像我期望的那样工作?上一个例子中的source: string | number不应该吗?

它是这样编译的:

type ParentType<S> = S extends string ? string : unknown
function test2<T>(scope: T): void {
let source: ParentType<T> | undefined = 'hello'
console.log(source)
}

我不明白这是怎么回事。

根据我的理解,这与条件类型在给定联合类型时变成分布类型有关(参见这里的手册)。

这失败:

type Generic<T> = T extends string ? T : T;
function test<T>(t: T): void {
const x: Generic<T> = t; // Type 'T' is not assignable to type 'Generic<T>'.
}

为了对抗分配行为,您可以将要检查的类型参数包装在元组中,这样就可以工作了:

type Generic<T> = [T] extends [string] ? T : T;
function test<T>(t: T): void {
const x: Generic<T> = t; // OK
}

对于您的示例,如果您像下面这样更改ParentScopeType,您将摆脱编译器错误:

export type ParentScopeType<S> = [S] extends [ScopeType<unknown>] ? S : S;

相关内容

最新更新