- bounty将在5天后过期**。回答此问题可获得+100的声誉奖励。OliverRadini正在寻找来自声誉良好的来源的答案。
我有一个类型定义来使一个类型不可变,我希望它能够一直确定属性的类型并使它们不可变,这个定义的代码如下(Immutable
)。
我的问题是,当我尝试将它用于泛型类型时,编译器确定这些类型不重叠,因此我不能将对象强制转换为不可变的。我尝试做的是能够使用我拥有的Immutable
的定义,但让它用于泛型。
如果我尝试不使用泛型,它会工作的很好。同样,如果我改变了不可变的定义(删除as T[K] extends (...args: Array<any>) => any ? never
),那么类型转换将使用泛型。所以我想这是与此有关的。
我对as T[K] extends (...args: Array<any>) => any ? never
的理解是,如果T
的属性K
是一个函数,那么就不要包含它;但是我可能错了,我最初并没有写这段代码。
下面是代码:
type Immutable<T> = T extends string | number | boolean | bigint | symbol | undefined | null
? Readonly<T>
: T extends object
? { readonly [K in keyof T as T[K] extends (...args: Array<any>) => any ? never : K]: Immutable<T[K]> }
: never;
interface IWithValue {
value: number;
}
interface IWithSelected<TData> {
selected: TData;
}
function f<T extends IWithValue>(
g: (x: Immutable<IWithSelected<T>>) => void,
x: IWithSelected<T>
) {
// This doesn't work because it doesn't believe the types overlap sufficiently
g(x as Immutable<IWithSelected<T>>);
}
function f2<T extends number>(
g: (x: Immutable<IWithSelected<T>>) => void,
x: IWithSelected<T>
) {
// Another generic using a number instead makes no difference
g(x as Immutable<IWithSelected<T>>);
}
function f3(
g: (x: Immutable<IWithSelected<{ a: 1 }>>) => void,
x: IWithSelected<{ a: 1 }>
) {
// Removing the generic removes the issue
g(x as Immutable<IWithSelected<{ a: 1 }>>);
}
function f4<T>(
g: (state: Immutable<IWithSelected<T>>) => void,
x: IWithSelected<T>
) {
// This one works
g(x as Immutable<typeof x>);
}
function f5<T>(
g: (state: Immutable<T>) => void,
x: T
) {
// This one works
g(x as Immutable<T>);
}
function f6<T>(
g: (state: Immutable<IWithSelected<T>>) => void,
x: IWithSelected<T>
) {
// This one gives as error
g(x as Immutable<T>);
}
上面的Playground链接
但是改变Immutable
的定义,错误就消失了:
type Immutable<T> = T extends string | number | boolean | bigint | symbol | undefined | null
? Readonly<T>
: T extends object
? { readonly [K in keyof T]: Immutable<T[K]> }
: never;
interface IWithValue {
value: number;
}
interface IWithSelected<TData> {
selected: TData;
}
function f<T extends IWithValue>(
g: (x: Immutable<IWithSelected<T>>) => void,
x: IWithSelected<T>
) {
// no error on this one
g(x as Immutable<IWithSelected<T>>);
}
上面的Playground链接
2条答案
按热度按时间fykwrbwg1#
在我看来,
a : T
与readonly_A : Immutable<T>
非常不同不能将强制转换为readonly_A。
你的类型是正确的,但是变量不正确。你需要的是将a转换为readonly_A,这不能是同一个示例。你需要的是你的对象的一个只读副本,以便传递给g函数。
这看起来很有效:
那么
ggazkfy82#
好吧,我想我明白了。
查看只读定义:类型只读= {只读[T的关键字中的P]:T[P]; };
和值类型的不可变异常:
我已测试只读:
所以这个宣言:
对这些类型进行标识。不变性是如此相似,我们可以删除异常:
所有演员现在都工作。(除了f6,但这一个应该崩溃)。
甚至更好的g(x)也是有效的。
游戏结束后有奖金