Creating Custom Types in Typescript
📣 Sponsor
Javascript is a dynamically typed language, which means we don't usually think about types. Typescript is strongly typed, which means everything has a type.
Occasionally we want to make an object or the return of a function conform to a certain format. This is where we use custom types. Typescript allows us to define our own custom types, which we can then use in our code.
Why would we use custom types?
Suppose you have a function that always returns data in a certain format, and uses an API to get that data. If the API returns data in the wrong format, we probably don't want the wrongly formatted data to end up in our code where it could cause issues. In such a case, we might ask that the return of a function conforms to a certain type. As such, we would define our own type.
Alias Types
One example of how to create types is called a
type Company = {
name: string,
address: string,
value?: number
}
If we give something the type Company
, then we expect it to have at least a name and address, and an optional value, which does not have to be given. As you can see, having a question mark in our type denotes that this property is optional.
If we were to use this in code, we might do something like this:
let myFunction = async function(): Promise<Company> {
let getApi = await fetch('/myApi/data', {
method: 'GET'
})
let getResult:Company = await getApi.json();
return getResult;
}
In the above code we are returning a Promise of type Company, and if we don't get that, we'll get an error. So for example, if we try to run this and we don't get an address or name back from our API, we will have an error which we can handle.
Extending Alias Types
You can extend alias types, i.e. if you want to add a new element to it. For example:
type Company = {
name: string,
address: string,
value?: number
}
type SubCompany = Company & {
identity: string
}
In the above, SubCompany will have everything Company has, plus a required attribute called identity.
Using Interfaces instead
Everything we've spoken about so far has been using the type
keyword, but we can do the same stuff using the interface
keyword instead. It is really personal preference which one you use. Our example above looks like this with interface
:
interface Company {
name: string,
address: string,
value?: number
}
interface SubCompany extends interface {
identity: string
}
Union Types
We can also define custom types using a much simpler syntax known as union types. Let's say we have a type which is either going to be a string or number, called myType. We could define that type as shown below:
type myType = number | string
Literal Types
This is where we set a type that has a specific list of values it can select from. Let's say our original type, Company, can only have three values, red, blue, or green. We can define a literal type, and use that as the type of our name attribute:
type Option = "blue" | "green" | "red"
type Company = {
name: Option,
address: string,
value?: number
}
More Tips and Tricks for Typescript
- How to setup a new Project in Typescript
- How to convert a String to a Number in TypeScript
- How the TypeScript Exclude Type Works
- How the TypeScript Parameters Type Works
- How TypeScript Default Parameters Work
- How Template Literal Types work in TypeScript
- How Typescript Enums Work
- Typescript Tuples, and how they work
- How the TypeScript Required Type Works
- How Typescript Generic Types Work