Disable allowing assigning Readonly types to non-readonly types












1















I've been looking at the readonly type in typescript. Sadly, it does not work as i hope it would. For instance, see the code below:



interface User{
firstName: string;
lastName: string;
}

const user: Readonly<User> = {
firstName: "Joe",
lastName: "Bob",
};

const mutableUser: User = user; //Is it possible to disallow this?

user.firstName = "Foo" //Throws error as expected
mutableUser.firstName ="Bar"//This works


Is it somehow possible to use the readonly type in a way that doesn't allow assigning it to another type that is not readonly? If it isn't can i solve it in any other way?










share|improve this question


















  • 1





    Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

    – Titian Cernicova-Dragomir
    Nov 21 '18 at 13:19
















1















I've been looking at the readonly type in typescript. Sadly, it does not work as i hope it would. For instance, see the code below:



interface User{
firstName: string;
lastName: string;
}

const user: Readonly<User> = {
firstName: "Joe",
lastName: "Bob",
};

const mutableUser: User = user; //Is it possible to disallow this?

user.firstName = "Foo" //Throws error as expected
mutableUser.firstName ="Bar"//This works


Is it somehow possible to use the readonly type in a way that doesn't allow assigning it to another type that is not readonly? If it isn't can i solve it in any other way?










share|improve this question


















  • 1





    Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

    – Titian Cernicova-Dragomir
    Nov 21 '18 at 13:19














1












1








1








I've been looking at the readonly type in typescript. Sadly, it does not work as i hope it would. For instance, see the code below:



interface User{
firstName: string;
lastName: string;
}

const user: Readonly<User> = {
firstName: "Joe",
lastName: "Bob",
};

const mutableUser: User = user; //Is it possible to disallow this?

user.firstName = "Foo" //Throws error as expected
mutableUser.firstName ="Bar"//This works


Is it somehow possible to use the readonly type in a way that doesn't allow assigning it to another type that is not readonly? If it isn't can i solve it in any other way?










share|improve this question














I've been looking at the readonly type in typescript. Sadly, it does not work as i hope it would. For instance, see the code below:



interface User{
firstName: string;
lastName: string;
}

const user: Readonly<User> = {
firstName: "Joe",
lastName: "Bob",
};

const mutableUser: User = user; //Is it possible to disallow this?

user.firstName = "Foo" //Throws error as expected
mutableUser.firstName ="Bar"//This works


Is it somehow possible to use the readonly type in a way that doesn't allow assigning it to another type that is not readonly? If it isn't can i solve it in any other way?







typescript immutability






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 '18 at 13:17









Erik JohanssonErik Johansson

323




323








  • 1





    Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

    – Titian Cernicova-Dragomir
    Nov 21 '18 at 13:19














  • 1





    Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

    – Titian Cernicova-Dragomir
    Nov 21 '18 at 13:19








1




1





Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

– Titian Cernicova-Dragomir
Nov 21 '18 at 13:19





Not possible currently.You maybe could do something for a function parameter to ensure the passed in parameter does not have readonly fields

– Titian Cernicova-Dragomir
Nov 21 '18 at 13:19












1 Answer
1






active

oldest

votes


















1














Ah, you've run into a problem that annoyed someone enough to file an issue with the memorable title "readonly modifiers are a joke" (which has since changed to something more neutral). The issue is being tracked at Microsoft/TypeScript#13347, but there doesn't seem to be much movement on it. For now, we just have to deal with the fact that readonly properties don't affect assignability.



So, what workarounds are possible?





The cleanest is to give up on readonly properties and instead use some kind of mapping that turns an object into something you really can only read from, via something like getter functions. For example, if readonly properties are replaced with functions that return the desired value:



function readonly<T extends object>(x: T): { readonly [K in keyof T]: () => T[K] } {
const ret = {} as { [K in keyof T]: () => T[K] };
(Object.keys(x) as Array<keyof T>).forEach(k => ret[k] = () => x[k]);
return ret;
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.firstName();
const lastName = user.lastName();

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, "Foo" is not a function
user.firstName = () => "Foo" // doesn't work because readonly


Or similarly, if a readonly object only exposes a single getter function:



function readonly<T extends object>(x: T): { get<K extends keyof T>(k: K): T[K] } {
return { get<K extends keyof T>(k: K) { return x[k] } };
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.get("firstName");
const lastName = user.get("lastName");

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, firstName not a property


It's annoying to use, but definitely enforces the spirit of readonliness (readonlity? 🤷‍♂️) and you can't accidentally write to something readonly.





Another workaround is to run a helper function which will only accept mutable values, as @TitianCernicova-Dragomir has suggested. Possibly, like this:



type IfEquals<T, U, Y = unknown, N = never> =
(<V>() => V extends T ? 1 : 2) extends
(<V>() => V extends U ? 1 : 2) ? Y : N;
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type IsMutable<T, Y=unknown, N=never> = IfEquals<T, Mutable<T>, Y, N>

const readonly = <T>(x: T): Readonly<T> => x;
const mutable = <T>(
x: T & IsMutable<T, unknown, ["OOPS", T, "has readonly properties"]>
): Mutable<T> => x;

const readonlyUser = readonly({
firstName: "Joe",
lastName: "Bob",
});
const mutableUser = mutable(
{ firstName: "Bob", lastName: "Joe" }
); // okay

const fails: User = mutable(readonlyUser); // error, can't turn readonly to mutable
// msg includes ["OOPS", Readonly<{ firstName: string; lastName: string; }>
// , "has readonly properties"]

const works = readonly(mutableUser); //okay, can turn mutable to readonly


Here the readonly function will accept any value of type T and return a Readonly<T>, but the mutable function will only accept values which are already mutable. You have to remember to call mutable() on any value you expect to be mutable. That's fairly error-prone, so I don't really recommend this method.





I also played around with the idea of making a fake Readonly<T> type which modified T in such a way as to distinguish it structurally from T, but it was as cumbersome as the getter-function method. The problem is that, assuming you want to be able to assign mutable values to readonly variables but you want to be prevented from assigning readonly values to mutable variables, the readonly modifier needs to widen the type of T, not narrow it. That limits the options to something like Readonly<T> = {[K in keyof T]: T[K] | Something} or Readonly<T> = T | Something. But in each case it becomes very difficult to actually read the readonly properties, since you have to narrow the types back. If you need boilerplate every time you read a property, you might as well use a getter function. So, forget that.





To wrap up: I think the getter function method is probably your best bet if you really want to enforce properties that cannot be written. Or maybe you should just give up on readonly modifiers, as they are, after all, a joke 🤡. Hope that helps. Good luck!






share|improve this answer
























  • This is exactly what i wanted to know. Thank you for a very detailed answer :)

    – Erik Johansson
    Nov 22 '18 at 14:00











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53412934%2fdisable-allowing-assigning-readonly-types-to-non-readonly-types%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














Ah, you've run into a problem that annoyed someone enough to file an issue with the memorable title "readonly modifiers are a joke" (which has since changed to something more neutral). The issue is being tracked at Microsoft/TypeScript#13347, but there doesn't seem to be much movement on it. For now, we just have to deal with the fact that readonly properties don't affect assignability.



So, what workarounds are possible?





The cleanest is to give up on readonly properties and instead use some kind of mapping that turns an object into something you really can only read from, via something like getter functions. For example, if readonly properties are replaced with functions that return the desired value:



function readonly<T extends object>(x: T): { readonly [K in keyof T]: () => T[K] } {
const ret = {} as { [K in keyof T]: () => T[K] };
(Object.keys(x) as Array<keyof T>).forEach(k => ret[k] = () => x[k]);
return ret;
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.firstName();
const lastName = user.lastName();

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, "Foo" is not a function
user.firstName = () => "Foo" // doesn't work because readonly


Or similarly, if a readonly object only exposes a single getter function:



function readonly<T extends object>(x: T): { get<K extends keyof T>(k: K): T[K] } {
return { get<K extends keyof T>(k: K) { return x[k] } };
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.get("firstName");
const lastName = user.get("lastName");

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, firstName not a property


It's annoying to use, but definitely enforces the spirit of readonliness (readonlity? 🤷‍♂️) and you can't accidentally write to something readonly.





Another workaround is to run a helper function which will only accept mutable values, as @TitianCernicova-Dragomir has suggested. Possibly, like this:



type IfEquals<T, U, Y = unknown, N = never> =
(<V>() => V extends T ? 1 : 2) extends
(<V>() => V extends U ? 1 : 2) ? Y : N;
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type IsMutable<T, Y=unknown, N=never> = IfEquals<T, Mutable<T>, Y, N>

const readonly = <T>(x: T): Readonly<T> => x;
const mutable = <T>(
x: T & IsMutable<T, unknown, ["OOPS", T, "has readonly properties"]>
): Mutable<T> => x;

const readonlyUser = readonly({
firstName: "Joe",
lastName: "Bob",
});
const mutableUser = mutable(
{ firstName: "Bob", lastName: "Joe" }
); // okay

const fails: User = mutable(readonlyUser); // error, can't turn readonly to mutable
// msg includes ["OOPS", Readonly<{ firstName: string; lastName: string; }>
// , "has readonly properties"]

const works = readonly(mutableUser); //okay, can turn mutable to readonly


Here the readonly function will accept any value of type T and return a Readonly<T>, but the mutable function will only accept values which are already mutable. You have to remember to call mutable() on any value you expect to be mutable. That's fairly error-prone, so I don't really recommend this method.





I also played around with the idea of making a fake Readonly<T> type which modified T in such a way as to distinguish it structurally from T, but it was as cumbersome as the getter-function method. The problem is that, assuming you want to be able to assign mutable values to readonly variables but you want to be prevented from assigning readonly values to mutable variables, the readonly modifier needs to widen the type of T, not narrow it. That limits the options to something like Readonly<T> = {[K in keyof T]: T[K] | Something} or Readonly<T> = T | Something. But in each case it becomes very difficult to actually read the readonly properties, since you have to narrow the types back. If you need boilerplate every time you read a property, you might as well use a getter function. So, forget that.





To wrap up: I think the getter function method is probably your best bet if you really want to enforce properties that cannot be written. Or maybe you should just give up on readonly modifiers, as they are, after all, a joke 🤡. Hope that helps. Good luck!






share|improve this answer
























  • This is exactly what i wanted to know. Thank you for a very detailed answer :)

    – Erik Johansson
    Nov 22 '18 at 14:00
















1














Ah, you've run into a problem that annoyed someone enough to file an issue with the memorable title "readonly modifiers are a joke" (which has since changed to something more neutral). The issue is being tracked at Microsoft/TypeScript#13347, but there doesn't seem to be much movement on it. For now, we just have to deal with the fact that readonly properties don't affect assignability.



So, what workarounds are possible?





The cleanest is to give up on readonly properties and instead use some kind of mapping that turns an object into something you really can only read from, via something like getter functions. For example, if readonly properties are replaced with functions that return the desired value:



function readonly<T extends object>(x: T): { readonly [K in keyof T]: () => T[K] } {
const ret = {} as { [K in keyof T]: () => T[K] };
(Object.keys(x) as Array<keyof T>).forEach(k => ret[k] = () => x[k]);
return ret;
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.firstName();
const lastName = user.lastName();

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, "Foo" is not a function
user.firstName = () => "Foo" // doesn't work because readonly


Or similarly, if a readonly object only exposes a single getter function:



function readonly<T extends object>(x: T): { get<K extends keyof T>(k: K): T[K] } {
return { get<K extends keyof T>(k: K) { return x[k] } };
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.get("firstName");
const lastName = user.get("lastName");

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, firstName not a property


It's annoying to use, but definitely enforces the spirit of readonliness (readonlity? 🤷‍♂️) and you can't accidentally write to something readonly.





Another workaround is to run a helper function which will only accept mutable values, as @TitianCernicova-Dragomir has suggested. Possibly, like this:



type IfEquals<T, U, Y = unknown, N = never> =
(<V>() => V extends T ? 1 : 2) extends
(<V>() => V extends U ? 1 : 2) ? Y : N;
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type IsMutable<T, Y=unknown, N=never> = IfEquals<T, Mutable<T>, Y, N>

const readonly = <T>(x: T): Readonly<T> => x;
const mutable = <T>(
x: T & IsMutable<T, unknown, ["OOPS", T, "has readonly properties"]>
): Mutable<T> => x;

const readonlyUser = readonly({
firstName: "Joe",
lastName: "Bob",
});
const mutableUser = mutable(
{ firstName: "Bob", lastName: "Joe" }
); // okay

const fails: User = mutable(readonlyUser); // error, can't turn readonly to mutable
// msg includes ["OOPS", Readonly<{ firstName: string; lastName: string; }>
// , "has readonly properties"]

const works = readonly(mutableUser); //okay, can turn mutable to readonly


Here the readonly function will accept any value of type T and return a Readonly<T>, but the mutable function will only accept values which are already mutable. You have to remember to call mutable() on any value you expect to be mutable. That's fairly error-prone, so I don't really recommend this method.





I also played around with the idea of making a fake Readonly<T> type which modified T in such a way as to distinguish it structurally from T, but it was as cumbersome as the getter-function method. The problem is that, assuming you want to be able to assign mutable values to readonly variables but you want to be prevented from assigning readonly values to mutable variables, the readonly modifier needs to widen the type of T, not narrow it. That limits the options to something like Readonly<T> = {[K in keyof T]: T[K] | Something} or Readonly<T> = T | Something. But in each case it becomes very difficult to actually read the readonly properties, since you have to narrow the types back. If you need boilerplate every time you read a property, you might as well use a getter function. So, forget that.





To wrap up: I think the getter function method is probably your best bet if you really want to enforce properties that cannot be written. Or maybe you should just give up on readonly modifiers, as they are, after all, a joke 🤡. Hope that helps. Good luck!






share|improve this answer
























  • This is exactly what i wanted to know. Thank you for a very detailed answer :)

    – Erik Johansson
    Nov 22 '18 at 14:00














1












1








1







Ah, you've run into a problem that annoyed someone enough to file an issue with the memorable title "readonly modifiers are a joke" (which has since changed to something more neutral). The issue is being tracked at Microsoft/TypeScript#13347, but there doesn't seem to be much movement on it. For now, we just have to deal with the fact that readonly properties don't affect assignability.



So, what workarounds are possible?





The cleanest is to give up on readonly properties and instead use some kind of mapping that turns an object into something you really can only read from, via something like getter functions. For example, if readonly properties are replaced with functions that return the desired value:



function readonly<T extends object>(x: T): { readonly [K in keyof T]: () => T[K] } {
const ret = {} as { [K in keyof T]: () => T[K] };
(Object.keys(x) as Array<keyof T>).forEach(k => ret[k] = () => x[k]);
return ret;
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.firstName();
const lastName = user.lastName();

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, "Foo" is not a function
user.firstName = () => "Foo" // doesn't work because readonly


Or similarly, if a readonly object only exposes a single getter function:



function readonly<T extends object>(x: T): { get<K extends keyof T>(k: K): T[K] } {
return { get<K extends keyof T>(k: K) { return x[k] } };
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.get("firstName");
const lastName = user.get("lastName");

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, firstName not a property


It's annoying to use, but definitely enforces the spirit of readonliness (readonlity? 🤷‍♂️) and you can't accidentally write to something readonly.





Another workaround is to run a helper function which will only accept mutable values, as @TitianCernicova-Dragomir has suggested. Possibly, like this:



type IfEquals<T, U, Y = unknown, N = never> =
(<V>() => V extends T ? 1 : 2) extends
(<V>() => V extends U ? 1 : 2) ? Y : N;
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type IsMutable<T, Y=unknown, N=never> = IfEquals<T, Mutable<T>, Y, N>

const readonly = <T>(x: T): Readonly<T> => x;
const mutable = <T>(
x: T & IsMutable<T, unknown, ["OOPS", T, "has readonly properties"]>
): Mutable<T> => x;

const readonlyUser = readonly({
firstName: "Joe",
lastName: "Bob",
});
const mutableUser = mutable(
{ firstName: "Bob", lastName: "Joe" }
); // okay

const fails: User = mutable(readonlyUser); // error, can't turn readonly to mutable
// msg includes ["OOPS", Readonly<{ firstName: string; lastName: string; }>
// , "has readonly properties"]

const works = readonly(mutableUser); //okay, can turn mutable to readonly


Here the readonly function will accept any value of type T and return a Readonly<T>, but the mutable function will only accept values which are already mutable. You have to remember to call mutable() on any value you expect to be mutable. That's fairly error-prone, so I don't really recommend this method.





I also played around with the idea of making a fake Readonly<T> type which modified T in such a way as to distinguish it structurally from T, but it was as cumbersome as the getter-function method. The problem is that, assuming you want to be able to assign mutable values to readonly variables but you want to be prevented from assigning readonly values to mutable variables, the readonly modifier needs to widen the type of T, not narrow it. That limits the options to something like Readonly<T> = {[K in keyof T]: T[K] | Something} or Readonly<T> = T | Something. But in each case it becomes very difficult to actually read the readonly properties, since you have to narrow the types back. If you need boilerplate every time you read a property, you might as well use a getter function. So, forget that.





To wrap up: I think the getter function method is probably your best bet if you really want to enforce properties that cannot be written. Or maybe you should just give up on readonly modifiers, as they are, after all, a joke 🤡. Hope that helps. Good luck!






share|improve this answer













Ah, you've run into a problem that annoyed someone enough to file an issue with the memorable title "readonly modifiers are a joke" (which has since changed to something more neutral). The issue is being tracked at Microsoft/TypeScript#13347, but there doesn't seem to be much movement on it. For now, we just have to deal with the fact that readonly properties don't affect assignability.



So, what workarounds are possible?





The cleanest is to give up on readonly properties and instead use some kind of mapping that turns an object into something you really can only read from, via something like getter functions. For example, if readonly properties are replaced with functions that return the desired value:



function readonly<T extends object>(x: T): { readonly [K in keyof T]: () => T[K] } {
const ret = {} as { [K in keyof T]: () => T[K] };
(Object.keys(x) as Array<keyof T>).forEach(k => ret[k] = () => x[k]);
return ret;
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.firstName();
const lastName = user.lastName();

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, "Foo" is not a function
user.firstName = () => "Foo" // doesn't work because readonly


Or similarly, if a readonly object only exposes a single getter function:



function readonly<T extends object>(x: T): { get<K extends keyof T>(k: K): T[K] } {
return { get<K extends keyof T>(k: K) { return x[k] } };
}

const user = readonly({
firstName: "Joe",
lastName: "Bob",
});

const mutableUser: User = user; // error, user is wrong shape

// reading from a readonly thing is a bit annoying
const firstName = user.get("firstName");
const lastName = user.get("lastName");

// but you can't write to it
user.firstName = "Foo" // doesn't even make sense, firstName not a property


It's annoying to use, but definitely enforces the spirit of readonliness (readonlity? 🤷‍♂️) and you can't accidentally write to something readonly.





Another workaround is to run a helper function which will only accept mutable values, as @TitianCernicova-Dragomir has suggested. Possibly, like this:



type IfEquals<T, U, Y = unknown, N = never> =
(<V>() => V extends T ? 1 : 2) extends
(<V>() => V extends U ? 1 : 2) ? Y : N;
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
type IsMutable<T, Y=unknown, N=never> = IfEquals<T, Mutable<T>, Y, N>

const readonly = <T>(x: T): Readonly<T> => x;
const mutable = <T>(
x: T & IsMutable<T, unknown, ["OOPS", T, "has readonly properties"]>
): Mutable<T> => x;

const readonlyUser = readonly({
firstName: "Joe",
lastName: "Bob",
});
const mutableUser = mutable(
{ firstName: "Bob", lastName: "Joe" }
); // okay

const fails: User = mutable(readonlyUser); // error, can't turn readonly to mutable
// msg includes ["OOPS", Readonly<{ firstName: string; lastName: string; }>
// , "has readonly properties"]

const works = readonly(mutableUser); //okay, can turn mutable to readonly


Here the readonly function will accept any value of type T and return a Readonly<T>, but the mutable function will only accept values which are already mutable. You have to remember to call mutable() on any value you expect to be mutable. That's fairly error-prone, so I don't really recommend this method.





I also played around with the idea of making a fake Readonly<T> type which modified T in such a way as to distinguish it structurally from T, but it was as cumbersome as the getter-function method. The problem is that, assuming you want to be able to assign mutable values to readonly variables but you want to be prevented from assigning readonly values to mutable variables, the readonly modifier needs to widen the type of T, not narrow it. That limits the options to something like Readonly<T> = {[K in keyof T]: T[K] | Something} or Readonly<T> = T | Something. But in each case it becomes very difficult to actually read the readonly properties, since you have to narrow the types back. If you need boilerplate every time you read a property, you might as well use a getter function. So, forget that.





To wrap up: I think the getter function method is probably your best bet if you really want to enforce properties that cannot be written. Or maybe you should just give up on readonly modifiers, as they are, after all, a joke 🤡. Hope that helps. Good luck!







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 16:37









jcalzjcalz

28.2k22750




28.2k22750













  • This is exactly what i wanted to know. Thank you for a very detailed answer :)

    – Erik Johansson
    Nov 22 '18 at 14:00



















  • This is exactly what i wanted to know. Thank you for a very detailed answer :)

    – Erik Johansson
    Nov 22 '18 at 14:00

















This is exactly what i wanted to know. Thank you for a very detailed answer :)

– Erik Johansson
Nov 22 '18 at 14:00





This is exactly what i wanted to know. Thank you for a very detailed answer :)

– Erik Johansson
Nov 22 '18 at 14:00




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53412934%2fdisable-allowing-assigning-readonly-types-to-non-readonly-types%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?