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?
CodePudding user response:
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>;
CodePudding user response:
Maybe you can try using TS "Enums",
Define your custom prop as follows,
enum CustomProp {
type1 = "type-1",
type2 = "type-2",
type3 = "type-3"
}
And then use it as follows,
const object = {
prop: "prop",
typedProp: CustomProp.type1,
};
W3Schools Guide: https://www.w3schools.com/typescript/typescript_enums.php