声明一个克隆函数以使只读属性在 TypeScript 中可写?

Mic*_*arf 8 typescript

我只读取了打字稿中的数据和一个clone函数:

class Data {
    readonly foo: string;
}

const ro: Data = {
    foo: 'bar'
}
// how to declare clone so that it returns writable data?
declare function clone<T>(val: T): T;

const rw = clone(ro);
// how to make the properties of rw writable?
rw.foo = 'changed';
Run Code Online (Sandbox Code Playgroud)

如何声明clone函数以便它返回的对象的属性是可写的?

knp*_*wrs 13

有一种更新的方法可以实现这一点,但我认为更新已经存在的答案并不是记录这一点的最佳方式。

type Mutable<T> = {
    -readonly [P in keyof T]: T[P];
};
Run Code Online (Sandbox Code Playgroud)

这具有保留可选修饰符并且只需要一个通用参数的额外好处。

操场上的代码


Nit*_*mer 5

目前的做法是:

type Mutable<T extends { [x: string]: any }, K extends string> = {
    [P in K]: T[P];
}

declare function clone<T>(val: T): Mutable<T, keyof T>;
Run Code Online (Sandbox Code Playgroud)

操场上的代码

如此处所述:删除修饰符的映射类型语法


原答案:

我很确定没有办法取消readonly限制,例如:

declare function clone<T>(val: T): {[K in keyof T]: T[K]};
const rw = clone(ro);
rw.foo = 'changed';
Run Code Online (Sandbox Code Playgroud)

仍然会产生只读错误。

不过,您可以做相反的事情,从“可写”接口开始并将其限制为只读:

interface Data {
    foo: string;
}

const ro: Readonly<Data> = {
    foo: 'bar'
}
declare function clone<T>(val: Readonly<T>): T;

const rw = clone(ro);
rw.foo = 'changed';
Run Code Online (Sandbox Code Playgroud)

请注意,我已从Data类更改为接口,因为您在示例中没有将其用作类。
如果你想将它作为一个类使用,你需要实例化它:

const ro = new Data();
ro.foo = "bar";
Run Code Online (Sandbox Code Playgroud)

或者

const ro = Object.assign(new Data(), { foo: "bar" });
Run Code Online (Sandbox Code Playgroud)

之前的编辑使用了一个被错误使用的错误:

我收回刚才的话,你实际上可以忽略 readonly 修饰符:

declare function clone<T>(val: T): {[K in (keyof T)]: T[K]};
const rw = clone(ro);
rw.foo = 'changed';
Run Code Online (Sandbox Code Playgroud)

工作正常,区别(keyof T)不仅仅是keyof T,还有一个问题:带有修饰符的映射类型错误被标记为错误。