As part of a code review a colleague recommended using a type rather than an enum. Whilst making the changes we found an issue neither of us expected.
We'd expect scenario one and two to throw compiler and/or intellisense errors as one of the values does not exist on the type. However, after testing we found only scenario one throws errors whilst scenario two resolves without issue.
This is likely an understanding issue but from everything I've read (e.g. Template Literal Types we should be getting errors when a provided value doesn't exist.
Based on the above, is anyone able to explain why we only see errors on scenario one but not the scenario two?
Scenario One
Example Code
export type FileType = ".png" | ".tif" | ".tiff" | ".jpeg" | ".jpg";
const allowedFileTypes = [".exe"] as Array<FileType>;
Expectation: Compiler error as .exe
doesn't exist
Outcome: Compiler error stating the value doesn't exist
Scenario Two
Example Code
export type FileType = ".png" | ".tif" | ".tiff" | ".jpeg" | ".jpg";
const allowedFileTypes = [".exe", ".jpeg"] as Array<FileType>;
Expectation: Compiler error as .exe
doesn't exist
Outcome: No compiler errors
Scenario Three
Example Code
export type FileType = ".png" | ".tif" | ".tiff" | ".jpeg" | ".jpg";
const allowedFileTypes = [".png", ".jpeg"] as Array<FileType>;
Expectation: No compiler errors
Outcome: No compiler errors
CodePudding user response:
as Type
is a way of saying "This value is this type, even if it doesn't look like it".
You're overriding normal type detection.
It's useful for things like:
const response = await fetch('/some/url');
const data = await response.json();
return data as Foo;
where you know what the shape of the data you are getting back from the HTTP request is, but the compiler has no way of telling that unless you use as
to tell it explicitly.
It is dangerous since you can specify a type that doesn't match the value you actually have (as you've discovered).
I have a project underway where I'm using superstruct in order to test the shape of my data inside a typeguard function instead of trusting to as
.
You need to specify what is allowed to be assigned to the variable instead:
const allowedFileTypes: Array<FileType> = [".exe", ".jpeg"];