Typescript has string literals which describe the valid string values for a type (see docs). My issue is that I can't get it to work when using plain JavaScript objects which it seemed to do in the past.
For example I would like to type the valid currencies for a product in a shopping basket.
interface Product {
title: string;
description: string;
price: number;
quantity: number;
currency: '$' | '£';
}
If I use a plain JavaScript object, let's say from a JSON source or JS file like this -
{
title: 'Y Lift Neck Serum',
description: 'This serum contains...',
price: 400,
currency: '$',
quantity: 1
}
I get the error - Types of property 'currency' are incompatible. Type 'string' is not assignable to type '"$" | "£"'.ts(2322) "typescript": "~3.7.2"
. This is because string literals are a subset of string and not a string.
The solutiouns I've found are to cast or use const but I'm wondering if there is a type definition for currency
that would "just work". I would rather not have to add const
or as
on multiple lines especially when the source file could be plain JavaScript or a server response.
What I also don't understand is how in another project this worked:
// "typescript": "^3.5.3"
export type Route = {
path: string;
method: '*' | 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS';
vhost?: string;
handler: (request, reply) => any;
options: object;
rules: object;
};
Update: I created a code demo https://codesandbox.io/s/summer-rgb-5ruv7 and the error does not appear there. But I can still see it in VS code - maybe its a local config issue?
Typescript config
{ // tsconfig.base.json
"compilerOptions": {
"target": "es5",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": false,
"noImplicitReturns": true,
"jsx": "preserve"
},
"exclude": ["node_modules", "build", "!node_modules/@types"]
}
{ // tsconfig.json
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"jsx": "react"
},
"include": ["src"]
}