class ResistorColor
{
private colors: string[]
public colorValues: any = {
grey: 8,
white: 9
}
}
'any' there means Typescript should not care about its type.
I want to replace 'any' by a type. How do we give proper types to such objects in Typescript?
class ResistorColor
{
private colors: string[]
public colorValues: any = {
grey: 8,
white: 9
}
}
'any' there means Typescript should not care about its type.
I want to replace 'any' by a type. How do we give proper types to such objects in Typescript?
Share Improve this question asked Mar 12, 2021 at 5:31 Aquarius_GirlAquarius_Girl 22.9k69 gold badges248 silver badges441 bronze badges 18- 4 Remove it entirely and let TS infer it. typescriptlang/play?#code/… – zerkms Commented Mar 12, 2021 at 5:33
-
2
I don't have
any
anywhere in my TS code and I hardly can think of any valid use case forany
that would pass my code review. – zerkms Commented Mar 12, 2021 at 5:40 -
2
@Aquarius_Girl letting typescript infer it is much, much better than
any
. Avoidany
at all costs! Setting a specific type like{grey: number; white: number;}
is fine but it's not neccessary. – Linda Paiste Commented Mar 12, 2021 at 5:41 -
2
"Why is it a problem?" --- the reason people choose TS is to write type safe code. Using
any
makes it unsafe again. What's the point of having TS then. – zerkms Commented Mar 12, 2021 at 5:45 -
3
@Aquarius_Girl If you really wanted to write "safe" code. You could create an interface like
interface Colors { grey: number; white: number; }
and then give your variable a type annotation likepublic colorValues: Colors { grey: 8, white: 9 }
– Tanner Dolby Commented Mar 12, 2021 at 6:02
2 Answers
Reset to default 5You do not want to use any
except in cases where you absolutely have to. any
means that a type can be literally anything so you have no information about what the type is. Typescript is not able to check for misuse of the variable because you've said "anything goes".
There are many ways to type this properly but here's one idea. You can define a type Color
which is the union of the string
names of all valid colors. Your private colors
is an array of these, so it would be Color[]
. Your public colorValues
is a mapping of colors to numbers so you can use the built-in utility type Record
to describe it as Record<Color, number>
which is an object where the keys are type Color
and the values are type number
. (If not all colors are present in the object then you would use Partial<Record<Color, number>>
for an inplete mapping).
type Color = 'grey' | 'white';
class ResistorColor
{
private colors: Color[] = []; // initial value avoids "not assigned in the constructor" error
public colorValues: Record<Color, number> = {
grey: 8,
white: 9
}
}
Typescript Playground Link
It might make sense to get the type Colors
from using typeof
on an array of color names, but I don't know where in your code you would have such an array or object with all of the colors. This might make sense if, for example, you initialized the colorValues
with some base value.
const colors = ['grey', 'white'] as const; // use as const to preserve string literals
type Color = (typeof colors)[number]; // indexed access by [number] to get the element type
// resolves to: type Color = "grey" | "white"
class ResistorColor {
public colorValues: Record<Color, number>;
constructor(baseVal: number = 0) {
this.colorValues = {} as Record<Color, number>; // need to make an `as` assertion when starting with an inplete object
colors.forEach(
color => this.colorValues[color] = baseVal
);
}
}
Typescript Playground Link
As others have mentioned, using any
as a type annotation in TypeScript doesn't help in writing safe code. It's better to avoid using type any
and let TypeScript try to infer the type through Type Inference.
If you wanted to provide an explicit type annotation for the colorValues
variable. You could create an interface or use a type alias, which acts as a blueprint to define the properties you expect the object to have.
interface Colors {
grey: number;
white: number;
}
public colorValues: Colors = {
grey: 8,
white: 9
}