3

I've been having issues with this for a while. The code does run without issue, but I feel like I should figure out what TypeScript's linter is concerned about. Here's the simplest repro I can get, LocaleConfig is what gets the red highlight.

let Today = new Date();
let LocaleConfig = {dateStyle: "full"};
console.log(Today.toLocaleString([], LocaleConfig));

I've noticed that the linter has different errors depending on the target version. Here's the result from the default ES3.

 No overload matches this call.
   Overload 1 of 3, '(locales?: LocalesArgument, options?: DateTimeFormatOptions | undefined): string', gave the following error.
     Argument of type '{ dateStyle: string; }' is not assignable to parameter of type 'DateTimeFormatOptions'.
       Types of property 'dateStyle' are incompatible.
         Type 'string' is not assignable to type '\"full\" | \"long\" | \"medium\" | \"short\" | undefined'.
   Overload 2 of 3, '(locales?: string | string[] | undefined, options?: DateTimeFormatOptions | undefined): string', gave the following error.
     Argument of type '{ dateStyle: string; }' is not assignable to parameter of type 'DateTimeFormatOptions'.
{source: ts, code: 2769, severity: 8}

And here's from ES6. Error is on the same word.

Type '{ dateStyle: string; }' has no properties in common with type 'DateTimeFormatOptions'.
{source: ts, code: 2559, severity: 8}
8
  • You've got me stumped. Never had a matching string literal complain like that before. But declaring the type of the property fixes it for me. let LocaleConfig: Intl.DateTimeFormatOptions = { dateStyle: 'full' }; Commented Sep 1, 2022 at 3:49
  • 1
    It is because when you just assign a string it is typed as a string. Which is wider than a type made up of string literal. So you have to assert the type in some way. What I did above (probably the best in this case), or just assert the one property as const: let localeConfig = { dateStyle: 'full' as const }; stackoverflow.com/a/37978675/9360315 Commented Sep 1, 2022 at 4:01
  • Does this answer your question? Typescript Type 'string' is not assignable to type Commented Sep 1, 2022 at 4:13
  • RE: declare property as DateTimeFormatOptions, that kinda just whack-a-moles the problem to the object literal on my end. VSCode, targeting either es3 or es6. "Type { dateStyle: string; } is not assignable to type DateTimeFormatOptions. Object literal may only specify known properties, and dateStyle does not exist in type DateTimeFormatOptions." Commented Sep 1, 2022 at 6:14
  • I'd added {dateStyle: 'full' as const}, but that new error persists. I also tried that other question's solution of declaring a new type with the appropriate choices, type Option = "full" | "long" | "medium" | "short" and {dateStyle: 'full' as Option}, but I'm still stuck on the previous error. Commented Sep 1, 2022 at 6:14

1 Answer 1

4

There are 2 separate issues here.

Type '{ dateStyle: string; }' has no properties in common with type 'DateTimeFormatOptions'.

This will happen when the target is set to anything pre ES2020, which is when the property was added to the spec. Find the draft here. ES6 == ES2015 and therefore it is missing when it is targeted.

Type 'string' is not assignable to type '"full" | "long" | "medium" | "short" | undefined'.

This is because of how string literals work. Without a type assertion, the dateStyle can only be determined to be of type string. Which could be changed at any time to be something not in the union of valid literals, which can therefore not reliably be assigned to it.

This can be resolved in multiple ways, but essentially you need to tell TS the dateStyle property is of some literal type or union of literal types that fits within the expected type.

We know the full expected type, so we can use that:
let LocaleConfig: Intl.DateTimeFormatOptions = { dateStyle: 'full' };
We could type assert as a literal in multiple ways:
let LocaleConfig = { dateStyle: 'full' as 'full' };
let LocaleConfig = { dateStyle: 'full' as 'full' | 'long' };
let LocaleConfig = { dateStyle: 'full' as Intl.DateTimeFormatOptions['dateStyle'] };
We could type assert as const in multiple ways:
let LocaleConfig = { dateStyle: 'full' as const };
let LocaleConfig = { dateStyle: 'full' } as const;

From TS handbook:

The as const suffix acts like const but for the type system, ensuring that all properties are assigned the literal type instead of a more general version like string or number.

Also found this answer around this problem.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.