Various types
Types
Here you can read about different types you can use in your code. You don't have to learn all of them in one go, just read them and come back to this section when you need to know how to apply a specific type.
Primitives
We have already looked at a few primitives, these were 'number', 'string' and 'boolean'.
let answer: number;
let name: string;
let isAmazing: boolean;
any
There is a type that is called 'any'. It means that you don't know the type and TypeScript will accept anything. You might need to use it while you are figuring out what datatype you actually need, but please replace it with a proper type before you commit your code.
let notSoNice: any;
Arrays
You can type an array by specifying what datatype it contains. For example an array of strings or numbers:
let names: string[];
names = ["John", "Jane", "Philippe"];
let ages: number[];
ages = [24, 65, 2];
Union types
Sometimes your property or parameter can be one of a few types. You can specify that by using a '|'.
function printId(id: number | string) {
console.log("Your ID is: " + id);
}
null and undefined
If you expect that your value could be empty you can type it as null or undefined. JavaScript sets variables to undefined if you don't assign it a value. If you choose to set a variable to be empty you can set it to null. Null and undefined are also primitives.
let numberOrNeverSet: number | undefined;
let numberOrSetToEmpty: number | null;
Literal types
You can also specify a literal type. An example of this is when you only want to allow specific strings.
let icon: "heart" | "star" | "sparkles";
icon = "star";
icon = "rain"; // TYPESCRIPT ERROR - Type 'rain' is not assignable to type 'heart' | 'star' | 'sparkles'
Type aliases
Sometimes you want to reuse a specific type you defined. You can make a type alias for that.
type Id = number | string;
function printId(id: Id) {
console.log("Your ID is: " + id);
}
let ids: Id[];
ids = [54, "22", "8", 231];
Object types
You can also define the type for an object.
let myBike: {
wheels: number;
brand: string;
isElectric: boolean;
};
myBike = {
wheels: 2,
brand: "Gazelle",
isElectric: false,
};
Optional properties
Sometimes a property is not required. You can specify this by adding a '?'
let myBike: {
wheels: number;
brand: string;
isElectric?: boolean;
};
myBike = {
wheels: 2,
brand: "Gazelle",
};
Interfaces
Object types can get large, and you might want to reuse them. In order to do that you can create interfaces.
interface Bike {
wheels: number;
brand: string;
isElectric?: boolean;
}
const myBike: Bike = {
wheels: 2,
brand: 'Gazelle',
};
const yourBike: Bike {
wheels: 1,
brand: 'Circus',
isElectric: true,
}
function hasWheels(bike: Bike) {
return bike.wheels > 0;
}
One of the main differences between types and interfaces in TypeScript is that types can be used to describe the shape of both objects and primitive values, while interfaces can only be used to describe the shape of objects. This means that if you want to describe the type of a primitive value, such as a number or a string, you will need to use a type.
Another difference between types and interfaces is that types can be more concise, since they allow you to define multiple related types in a single statement using the union operator (|). Interfaces, on the other hand, require you to define each type separately. However, you can extend interfaces:
interface RentedBike extends Bike {
contactNumber: string;
startDate: string;
endDate: string;
}
Methods
You can also type methods (functions that are present in objects). You can type both their parameters and their return value. When the method returns nothing you can say that it retuns 'void'.
interface Bike {
wheels: number;
brand: string;
isElectric?: boolean;
onDrive: (speed: number) => void;
getAmountOfWheels: () => number;
}
const myBike: Bike {
wheels: 2,
brand: 'Gazelle',
onDrive: (speed) => console.log(speed);
getAmountOfWheels: () => return this.wheels;
}
Angle bracket notation
Some types need another type to complete it. That second type is then written between <
and >
. One of these is the array type we covered earlier. You write the array type in two different ways. Both of these mean that this type is an array of strings.
let names: string[];
// Means exactly the same as:
let names: Array<string>;
Types in React
When we installed TypeScript we also installed some specific types that help TypeScript understand and type React code. You can use these to be more specific about your React components.
When you define a React component you are doing that by using Functional Components. They are called Functional because they are basically a function that you export and use in your code as a component. In the examples above we already learned how to type function parameters and their return values. Let's now use that for our React components.
Properties
More important than specifying the return type is specifying the props your component uses. This will help you later when you use the component, by telling you what props to pass it.
Because your properties are an object you could use an interface to type them:
interface MyComponentProps {
icon: "heart" | "star" | "sparkles";
onClick?: () => void;
}
function MyComponent({ icon, onClick }: MyComponentProps) {
// You component code
}
// Or the same function using arrow notation
const MyComponent = ({ icon, onClick }: MyComponentProps) => {
// Your component code
};
If you use the arrow notation you can even combine the return and property types by using a type for React Function Components:
const MyComponent: React.FunctionComponent<MyComponentProps> = ({ icon, onClick }) => {
...
}
Hooks
You can also type your hooks:
const [isAwesome, setIsAwesome] = React.useState(true);
// You don't need to type this state because TypeScript infers it is a boolean
const [user, setUser] = React.useState<User | null>(null);
// This type says that the state can either be of type User or set to be empty (null)
Styled Components
You will also need to define types when passing props to styled components. You can do this in multiple ways:
export const Hamburger = styled.img<{ isMenuOpen: boolean }>`
display: ${(props) => (props.isMenuOpen ? "none" : "block")};
`;
Or by defining an interface (we're also destructuring props
here):
interface StyledProps {
isMenuOpen: boolean;
}
export const Hamburger = styled.img`
display: ${({ isMenuOpen }: StyledProps) => (isMenuOpen ? "none" : "block")};
`;
Further reading
For more examples in React you can check out the React TypeScript cheatsheet.