- What is TypeScript Type System?
- What are TypeScript Types?
- What are Utility Types in TypeScript?
- 1. Pick<Type, Keys>
- 3. Exclude<UnionType, ExcludedMembers>
- 4. Required<Type>
- 5. Partial<Type>
- 7. Parameters<Type>
- 8. ReturnType<Type>
- 11. NonNullable<Type>
- Intrinsic String Manipulation Types
- Difference Between TypeScript Type and Interface?
- Difference Between TypeScript Type and Class?
- Wrapping Up
The common data types in typescript will be covered in this article along with examples of how they are used.
What is TypeScript Type System?
TypeScript type system refers to the different data types and their supported operations that are allowed in typescripts. This means that when you create a variable of type number, you cannot assign a type string or perform a string operation on it.
What are TypeScript Types?
TypeScript is the superset of vanilla JavaScript (that provides types to JavaScript es6), therefore it includes all JavaScript data types and adds additional type safety to them with additional types. Types in TypeScript are a mechanism to describe the kind of value a variable will have.
TypeScript types include the three commonly used primitive types in JavaScript:
- String
- Number
- Boolean
What is the Default Type in TypeScript?
Any is the default data type in TypeScript when no type is specified, which allows any kind of value to be assigned afterward without constraints because any keyword turns off type-checking in TypeScript.
When should I use any type?
You can use any data type to avoid type checking or type errors especially when you’re unsure of the type of the variable which is common when working with third-party APIs.
What is Keyof Type Operator in TypeScript?
The keyof type is used to generate a union of an object key in order to ensure correct type checking of the property key associated with the object.
Given that we have an interface for an object that only has 3 keys; name, age, and canVote properties.
interface Voter {
name: string,
age: number
canVote: boolean,
}
Which can be represented in an object like this
const person = {
name: "Sam",
age: 23,
canVote: true
}
The union of the keys above will be “name” | “age” | “canVote”, any other key apart from these properties is invalid.
If we have a function that needs to access the value of the object using the key property, we can use the keyof to ensure that the key passed to the function as an argument is valid:
const personVotingStatus = (person: Voter, property: keyof Voter) =>{
return console.log(`Person ${person[property] ? "can vote" : "cannot vote"}`)
}
When we passed a valid key to the function as an argument, the function will run as expected:
personVotingStatus(person, "canVote")
Output:
But when we try passing an invalid key as an argument, like this:
personVotingStatus(person, "canVoted") // wrong key
A warning will be displayed within our code even before the code is compiled:
Our output will also result in the wrong condition:
As demonstrated above, the keyof keyword operator helps us to catch errors early when we pass an invalid key property to access a value in an object.
You can find the complete source code for keyof on the Codesandbox TypeScript playground here.
What are Utility Types in TypeScript?
TypeScript supports several other types apart from string, number, and boolean. Some of the other types include the utility types are global types that can be used for type manipulation and transformation within our program.
1. Pick<Type, Keys>
The Pick type can be used to create a new set of allowed keys from an object’s existing key properties.
Given that we have an object interface with 3 keys name, age, and canVote keys:
interface Voter {
name: string,
age: number
canVote: boolean,
}
And we want to only accept the name of every new voter without their age and canVote status. We can apply the Pick type to achieve this:
const personVoteStatus: Pick<Voter, "name"> = {
name: "sam",
}
The Pick keyword will only allow the name property to be created in the new object, while every other key like age, canVote, etc will be void, as shown below:
How to set multiple keys in the Pick type?
Let’s assume we want to accept both name and age of every new voter. We can make use of the union of type string literals, like this:
const personVoteStatus: Pick<Voter, "name" | "age"> = {
name: "sam",
age: 23
}
The age key is now a valid property for the new voter objects and the error displayed for the age key earlier will be removed:
2. Omit<Type, Keys>
The Omit type is used to remove keys from an existing key of an object. Say we want to disallow the name key property from every new Voter:
interface Voter {
name: string,
age: number
canVote: boolean,
}
Our Omit expression will be:
const voter: Omit<Voter, "name" > = {
name: "sam",
age: 23,
canVote: true
}
The name property will throw an error because it has been omitted from the allowed key properties for every voter’s object.
How to omit multiple keys in the Omit type?
Let’s assume we want to omit both name and age of every new voter object. We can make use of the union of string literals, like this:
const personVoteStatus: Omit<Voter, "name" | "age"> = {
name: "sam",
age: 23,
canVote: true
}
The name and age keys will throw an error when added to the object.
3. Exclude<UnionType, ExcludedMembers>
The Exclude type is used to remove a type from a union of types. Given that we set the type of variable age to be either a string, number, or a boolean, like this:
type Age = string | number | boolean
If we want to disallow any of the union types that we’ve declared, we can make use of the Exclude type.
Say we want to disallow the boolean type from the age variable, our expression will look something like this:
const age: Exclude<Age, boolean> = true
We’ll get an error if we then assign a boolean value to the age variable.
We can also exclude multiple members of the union as well, like this:
const age: Exclude<Age, boolean | number> = "23"
4. Required<Type>
The Required type is used to set all the key properties in an object type as required, even if they’re initially set as optional.
interface Voter {
name: string,
age: number
canVote: boolean,
}
const personVoteStatus: Required<Voter> = {
age: 23,
canVote: true
}
An error will occur because the name key property is missing from the new object and all the keys in the object type are required.
The Require type is the opposite of the Partial type.
5. Partial<Type>
The Partial type is used to set the keys in an object type to optional even if they’re initially set as required.
interface Voter {
name: string,
age: number
canVote: boolean,
}
const voter: Partial<Voter> = {
age: 23,
canVote: true
}
Our code will execute without any warnings or errors.
6. Record<Keys, Type>
The Record utility type in TypeScript is used to construct an object whose property keys are keys and values are Type. The Record utility is useful for mapping the properties of a type to another type.
Given that we have an interface for voters:
interface Voter {
name: string,
age: number
canVote: boolean,
}
And we have three unions of voters, which are declared like this:
type Voters = "Sam" | "Mike" | "Cyntia"
We can use the Record utility type to create an object of voters like this:
const voters: Record<Voters, Voter> = {
Sam: {name: "Samuel Adebayo", age: 23, canVote: true},
Mike: {name: "Mike Doe", age: 18, canVote: false},
Cyntia: {name: "Cyntia Mogan", age: 30, canVote: true},
}
Any other key other than Sam, Mike, and Cyntia will be invalid.
7. Parameters<Type>
The Parameters type in TypeScript can be used to create an array of the data types of a function’s parameter, which can then be used as a type of another structure.
Given that we have a processVoter function that accepts two parameters name and age with type string and number as their data type respectively:
const processVoter = (name: string, age: number) =>{
return `Voter's name is ${name} and ${age} years old`
}
Instead of manually creating the type of the voter’s array value or updating it with new types, like this:
const voter: [string, number] = ["sam", 23]
We can create an expected data type using the Parameters Type, like this:
type ExpectedVoterType = Parameters<typeof processVoter>
Then we’ll pass the ExpectedVoterType to our array of arguments:
const voter: ExpectedVoterType = ["sam", 23]
Then invoke the function with the argument using the spread operator:
console.log(processVoter(...voter))
Our code output will be:
This method will make our code more readable, as well as easier to scale and maintain.
8. ReturnType<Type>
The ReturnType utility type in TypeScript is used to extract the data types of the return value of a function type.
Given that a function will return an id and name with a data type of number and type string respectively.
type votersCardGenerator = () => { id: number, name: string };
We can set the type of an object to be the same as the return type of the function, like this:
const votersCard: ReturnType<votersCardGenerator> = {
id: 120,
name: "Samuel"
}
This is to ensure that the data type of the object is the same as that of the returned value of a function when executed.
TypeScript will throw an error when we pass a different data type that is different from the return type of a function.
9. Readonly<Type>
The Readonly type in TypeScript is used to construct a read-only, unchangeable property of a specific type.
Given that we want to construct a read-only object type, our expression will look something like this:
interface Voter {
name: string,
age: number,
canVote: boolean
}
const voter: Readonly<Voter> = {
name: "sam",
age: 23,
canVote: false
}
If we attempt to reassign any property in the voter object, like this:
voter.canVote = true
TypeScript will throw an error that the property is a read-only property and cannot be reassigned:
10. Extract<Type, Union>
The Extract type in TypeScript is used to extract the subset of a type from another type.
Given that we have a type of Age variable that accepts either a string or a number:
type Age = string | number
We can extract part of the Age variable type like this:
const age : Extract<Age, number> = 23
From the above expression, we’re extracting the type number from the Age type.
Now TypeScript will throw an error when we assign a string value to the age variable:
11. NonNullable<Type>
The NonNullable type in TypeScript can be used to construct a new type that excludes the undefined and null types from the current union type.
Given that we have a type age variable that accepts either string, number, undefined, or null data types.
type Age = string | number | undefined | null
If we need to reuse the same type of age variable without the undefined and null data types, we can make use of the NonNullable type, like this:
const age : NonNullable<age> = undefined
TypeScript will now throw an error when we try to set undefined or null to the age variable as shown below:
12. Awaited<Type>
The Awaited type in TypeScript is modeled to handle the asynchronous response in JavaScript functions such as await in async functions and the .then function in promise.
- The Awaited type can be used for a string
type basic = Awaited<Promise<string>>;
type recursive = Awaited<Promise<Promise<string>>>;
- The Awaited type can be used for a boolean
type nonThenObj = Awaited<boolean>;
- The Awaited type can be used for union results i.e string | date
type unions = Awaited<Date | Promise<Promise<string>>>;
Intrinsic String Manipulation Types
These are special built-in string manipulation types that are useful for converting characters to different case versions.
1. Uppercase<StringType>
The Uppercase type can be used to convert all characters in a type string to an UPPERCASE version.****
type Name = "samuel"
type UppercaseName = Uppercase<Name> // Output: "SAMUEL"
2. Lowercase<StringType>
The Lowercase type can be used to convert all characters in a string to a lowercase version.
type Name = "SAMUEL"
type UppercaseName = Lowercase<Name> // Output: "samuel"
3. Capitalize<StringType>
The capitalize type can be used to convert the first character in a type string to a Capital letter.
type Name = "samuel"
type UppercaseName = Capitalize<Name> // Output: "Samuel"
4. Uncapitalize<StringType>
The uncapitalize type can be used to convert every character except the first letter in a type string to a capital letter.
type Name = "SAMUEL"
type UppercaseName = Uncapitalize<Name> // Output: "sAMUEL"
Difference Between TypeScript Type and Interface?
The main difference between typescript type and interface is that a type is a definition of a data type, such as a union, primitive, intersection, tuple, or any other type while interfaces are simply a way to describe data shapes, such as shape to javascript objects and JavaScript ES6 classes.
Checkout the video below for a video explanation:
Difference Between TypeScript Type and Class?
A type is a definition of a data type, such as a union type, primitive, intersection, tuple, or any other type while classes in TypeScript are the object factories or blueprints of an object and it expresses the logic, methods, and properties these objects will inherit.
Wrapping Up
In this article, we looked at what TypeScript types are and how some of the most often-used types work.
I hope this tutorial has assisted you in understanding the fundamentals and applications of TypeScript types for building a TypeScript web app. Make sure to revisit a previous example in this article when needed!
Finally, you can find more awesome articles like this on our blog at CopyCat. CopyCat is a tool that saves you about 35% of development time by converting your Figma files to an up-and-running React project. Check it out here.
Interesting Reads From Our Blogs
- 10 CSS Frameworks for Frontend Developers in 2022
- Your Introductory Guide to React Intl
- The Top 16 Design System Examples
Check out the CopyCat plugin for React if you’re seeking for amazing React tools to help you build component code faster and be production ready sooner than your competition!
Happy Coding!