Disable allowing assigning Readonly types to non-readonly types
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
add a comment |
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
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
add a comment |
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
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
typescript immutability
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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!
This is exactly what i wanted to know. Thank you for a very detailed answer :)
– Erik Johansson
Nov 22 '18 at 14:00
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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!
This is exactly what i wanted to know. Thank you for a very detailed answer :)
– Erik Johansson
Nov 22 '18 at 14:00
add a comment |
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!
This is exactly what i wanted to know. Thank you for a very detailed answer :)
– Erik Johansson
Nov 22 '18 at 14:00
add a comment |
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!
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!
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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