Reputation: 151
I have the following code that works perfectly:
const option = {
year: "numeric",
month: "short",
day: "numeric",
weekday: 'long',
}
const myDate = new Intl.DateTimeFormat('de', {
year: "numeric",
month: "short",
day: "numeric",
weekday: 'long',
}).format(date)
const myDateTest2 = new Intl.DateTimeFormat('de', option as any).format(date)
This means I get a date if I pass the object directly into the constructor.
It also works if I define the options first and then use any
.
But this is throwing a TypeScript error:
const myDateTest = new Intl.DateTimeFormat('de', option).format(date)
as follows:
Argument of type '{ year: string; month: string; day: string; weekday: string; }' is not assignable to parameter of type 'DateTimeFormatOptions'.
Types of property 'weekday' are incompatible.
Type 'string' is not assignable to type '"short" | "long" | "narrow"'.ts(2345)
Why is this?
I tried multiple TS configurations, but none of them solve the issue.
Here is what I have now:
"compilerOptions": {
"allowJs": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "ES2020",
"sourceMap": true,
"outDir": "./.tmp/build/",
"moduleResolution": "node",
"declaration": true,
"lib": [
"ES2020",
"ES2020.Intl",
"dom"
],
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
},
TypeScript version is "typescript": "^4.8.4",
Upvotes: 1
Views: 2508
Reputation: 42160
What you are experiencing here is a common problem when dealing with functions that require string literal types in their arguments. It's nothing specific to Intl.DateTimeFormat
. You can read the docs on Literal Inference for more info.
Let's take a look at what your error is telling you:
Argument of type '{ year: string; month: string; day: string; weekday: string; }' is not assignable to parameter of type 'DateTimeFormatOptions'.
Types of property 'weekday' are incompatible.
Type 'string' is not assignable to type '"short" | "long" | "narrow"'.ts(2345)
The type of your option.weekday
is inferred as string
. This is not specific enough for the Intl.DateTimeFormat
constructor, which only allows three possible string literal values: "short" | "long" | "narrow"
.
The value of your option
variable is fine. But TypeScript only looks at types, not values.
When you write your assignment statement like this:
const option = {
year: "numeric",
month: "short",
day: "numeric",
weekday: "long",
}
TypeScript infers the type as:
const option: {
year: string;
month: string;
day: string;
weekday: string;
}
We need to create your variable in a way that will give it a narrower type.
We know from your error that the type which your option
variable needs to fit is Intl.DateTimeFormatOptions
. We can use that type when you create the option
variable.
const option: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "numeric",
weekday: "long",
}
TypeScript will check each of the properties of your object to make sure that they are assignable to the constraints of the Intl.DateTimeFormatOptions
type.
If you provide an invalid value, like this:
const option: Intl.DateTimeFormatOptions = {
weekday: "numeric",
}
You'll see a red underline on the weekday
property. I prefer this approach for that reason -- it is easier to see exactly where the problems are. For weekday: "numeric"
your error message would be:
Type '"numeric"' is not assignable to type '"long" | "short" | "narrow" | undefined'
as const
You can change the way that TypeScript infers the type by using an as const
statement when you create your variable. This tells TypeScript to treat all properties of your object as their literal types (explained here).
const option = {
year: "numeric",
month: "short",
day: "numeric",
weekday: "long",
} as const;
TypeScript infers the type as:
const option: {
readonly year: "numeric";
readonly month: "short";
readonly day: "numeric";
readonly weekday: "long";
}
Each property has a string literal type like "long"
rather than just string
.
Assuming that your values are valid, these literal types will be assignable to the broader Intl.DateTimeFormatOptions
type. For example, "long"
is assignable to the union type '"short" | "long" | "narrow"'
on the weekday
property.
Upvotes: 9