Issue
Let's say there is an object that looks like this:
const object = {
prop: "prop",
typedProp: "type-1",
};
I want the typedProp property to only accept the following values: "type-1", "type-2", "type-3". To do this, I created a custom type that looks like this:
type CustomProp = "type-1" | "type-2" | "type-3";
I know that I can assign this type like so:
const object: {
prop: string;
typedProp: CustomProp; // <-- Adding type here
} = {
prop: "prop",
typedProp: "type-1",
};
My question is, is there a way to assign this type directly to typedProp (within the object) so that I can avoid adding the type to the whole object? I tried to implement it this way:
const object = {
prop: "prop",
typedProp: "type-1" as CustomProp,
};
but it doesn't work as expected, because with this approach, I can add any string to typedProp, which is not what I would like to achieve. Could you please advise if there is a way to do this?
Solution
You're looking for a "safe upcast" operator, or a "widening-only type assertion". TypeScript doesn't have direct support for such a thing. There's long been discussion of (and possibly soon there will be an implementation of) the so-called satisfies operator, the subject of microsoft/TypeScript#7481 and now microsoft/TypeScript#47920, which some people want for reasons like this, although it looks like the "safe upcast" part won't be supported. So for the foreseeable future there's not going to be syntax that does this for you.
Luckily you can emulate this with a helper function.
The function const customProp = (t: CustomProp) => t will only accept a CustomProp input, and will return its input with the type CustomProp. There won't be any widening to string or narrowing to just the single "type-1" string literal type:
const customProp: (t: CustomProp) => t;
const badObject = {
prop: "prop",
typedPop: customProp("oopsie-doodle") // error!
}
const object = {
prop: "prop",
typedProp: customProp("type-1"), // okay
};
object.typedProp = "type-2"; // okay
If you find yourself doing this sort of thing often, you can write a generic version of this function that accepts a value of manually specified type T and returns that value with a non-widened non-narrowed type T:
const safeUpcast = <T,>(t: T) => t;
And then the customProp function is just a special case of safeUpcast instantiated with T being CustomProp:
const customProp = safeUpcast<CustomProp>;
Answered By - jcalz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.