The Problem
type Roles = "student" | "teacher";
type Person = {
role: Roles;
name: string;
age: number;
}
function doSomethingWithPerson(person: Person) {
console.log(person);
}
const andy = {
role: "teacher",
name: "andy",
age: 31
};
doSomethingWithPerson(andy); //Argument of type '{ role: string; name: string; age: number; }' is not assignable to parameter of type 'Person'.
This code produces the error:
Argument of type '{ role: string; name: string; age: number; }' is not assignable to parameter of type 'Person'.
Types of property 'role' are incompatible.
Type 'string' is not assignable to type 'Roles'.
What's going on here?
The andy
object we declare does match the type Person
that the function wants, so why is TypeScript complaining?
Quick Solution
Declare the string "teacher"
as const
const andy = {
role: "teacher" as const,
name: "andy",
age: 31
};
doSomethingWithPerson(andy);
Explanation
In this scenario when we declare the object andy
TypeScript infers the type of the role
property as string
, any string!
While "teacher"
and "student"
are strings, they are a subset of strings.
The Person
type doesn't want any string, it wants just those two particular strings.
That TypeScript infers the type as string
and not as "teacher"
is called type widening.
What TypeScript is doing, is allowing for that you might later write some code like:
andy.role = "foobar";
(That is, you're mutating the andy
object).
What the as const
keyword does is just prevent the type widening. See the documentation here.
What you're also doing is telling TypeScript 'don't worry, I promise I'm not going to reassign this property', and if you try, TypeScript will give you an error:
const andy = {
role: "teacher" as const,
name: "andy",
age: 31
};
andy.role = "foobar"; //Type '"foobar"' is not assignable to type '"teacher"'.(2322)
Alternative solutions
Declare the string "teacher"
as "teacher"
const andy = {
role: "teacher" as "teacher",
name: "andy",
age: 31
};
doSomethingWithPerson(andy);
What this does is instead of using the as const
keyword to prevent type widening, it just explicitly sets the type of the role
property to "teacher"
.
Both as const
and as "teacher"
have the same end effect, the role
property's type is "teacher"
.
Top comments (0)