# Typescript
v4.2
Resources
- Reference (opens new window)
- typescriptlang.org (opens new window)
- Typescript + React
- reactjs.org/docs/static-type-checking (opens new window)
- github.com/piotrwitek/react-redux-typescript-guide (opens new window)
- github.com/typescript-cheatsheets/react (opens new window)
- sitepoint.com/react-with-typescript-best-practices/ (opens new window)
- Youtube - React+Typescript app example (opens new window)
- (Archived) Microsoft/TypeScript-React-Conversion-Guide (opens new window)
# install
yarn add typescript
tsc index.js
tsc index.js -w # watch
# create tsconfig.json
tsc --init
# watch if tsconfig.json is configured
tsc -w
tsconfig.json
{
"compilerOptions": {
"target": "ES6",
// "lib": ["dom", "es6"],
"rootDir": "./src",
"outDir": "./dist"
}
}
# Everyday Types
# Types
Importance | Types |
---|---|
High | string, boolean, number, Array[] |
Medium | object{}, tuple, enum, Function |
Low | null, void, unknown |
Avoid | any, never, undefined |
# Implicit/Explicit
// implicit - const vs let
const foo = 'hello world'; // foo: "hello world" - a Literal type
let foo = 'hello'; // foo: string
// Explicit types - only let
let foo: string = 'a string';
let foo: number = 5;
let foo: string[] = ['foo', 'bar'];
# Literal type
interface User {
name: string;
gender: 'male' | 'female' | 'unspecified'; // not string but specific values only
}
let user: User = {
name: 'umesh',
gender: 'male',
};
# Array
const foo: number[] = [1, 3];
const foo: readonly number[] = [1, 3];
const bar: Array<number> = [1, 3]; // same as above
const bar: ReadonlyArray<number> = [1, 3]; // push/pop not possible
const doo: [number, string] = [1, 'hello']; // TUPLE - fixed number(and types) of items
# Function type
// Ex - Function type
let foo: Function;
// foo = 3; // error
// Ex - () => {}
let myFunc: (a: number, b: number) => number = (x, y) => {
return x + y;
};
// Ex - callback
let myFunc2: (a: number, cb: (x: number) => number) => number = (
x,
callback
) => {
return callback(x);
};
let twice = (num: number) => num * 2;
let thrice = (num: number) => num * 3;
console.log(myFunc2(5, twice)); // 10
console.log(myFunc2(5, thrice)); // 15
# Object
const user: {name: string; age: number; gender?: string} = {
name: 'umesh',
age: 31,
// gender: 'male' // optional property
};
# Union
// Union function
let getLen = (params: string | string[]) => {
return params.length;
};
getLen('foo'); // 3
getLen(['foo', 'bar']); // 2
getLen(23); // error
# Interfaces & Type Aliases
- Almost similar.
- Can be used together too.
|
|
# Type vs Interface
type
is immutable.
|
|
# Type casting/assertion
- Type assertion is not same as casting.
// --- ex
let page: unknown = '23';
let pageNumber = page as number;
// --- ex
let page: string = '23';
let pageNumber = (page as unknown) as number;
// --- ex
const x = 'hello' as number; // error
const x = ('hello' as unknown) as number; // works
// assertion means here code temporarily lies to compiler
// that {} is of type IUser since it will be set soon
const [user, setUser] = React.useState<IUser>({} as IUser);
// later...
setUser(newUser);
# null/undefined
- use
!
at end of variable - value isn’t null or undefined - see Working with DOM below
# Unknown type
// UNKNOWN
let foo: unknown;
let bar: string;
foo = 23;
foo = 'umesh';
// case 1
bar = foo; // error
// case 2
if (typeof foo === 'string') {
bar = foo; // no error
}
# Never type
- return type of function
function generateErrorVoid(message: string, code: number): void {
// return ; // no error
return ''; // error (string is returned)
}
function generateError(message: string, code: number): never {
// return; // error
throw {message: message, errCode: code}; // useful
}
# Interfaces
// first letter is capital
// class = User and interface = UserInterface
interface UserInterface {
name: string;
age: number;
hobby?: number; // optional
greet(): string; // return type
}
let user: UserInterface = {
name: 'foo',
age: 23,
// error - greet is missing error
};
# Working with DOM
// Note - Use `.ts` file and not typescript Playground
// input
let input = document.querySelector('#name'); // error
// case 1 - add !
let input = document.querySelector('#name')!; // no error - adding ! means #name will be definately available during runtime
// case 2 - add type check
let input = document.querySelector('#name'); // just adding ! means #name will be definately available during runtime
if (input) {
// code
}
let input = document.querySelector('#name') as HTMLInputElement;
let value = input.value;
// add listener
input.addEventListener('click', (event) => {
let target = event.target as HTMLInputElement;
console.log(target.value);
});
# Classes
private, protected, public
class User {
id: number; // public is default
protected name: string;
private age: number;
readonly something: string;
static readonly blablah: string = 'hooohaaaa'; // User.blablah
constructor(name: string, age: number) {
this.name = name;
this.age = age;
this.something = name + age; // readonly except in constructor
}
}
let foo = new User('foooo', 23);
// interface
interface UserInterface {
greet(): string;
}
class User implements UserInterface {
// code something
greet() {
return 'Hello';
}
}
// inheritance
class Admin extends User {
// code
}
# Generics in Typescript
- Generics allows us to provide different datatypes ie dynamic datatypes
<T>
means we can provide different datatypes
// <T> - no constraint and T can be anything
// <T extends object> - constraint that T must be object only
// add constraint - <T> must be object
const addId = <T extends object>(obj: T) => {
let id = Math.random().toString(16);
return {
id,
...obj,
};
};
interface UserInterface {
name: string;
}
let user: UserInterface = {
name: 'foo',
};
// let result = addId(user); // works (implicit)
let result = addId<UserInterface>(user); // better reading (explicit)
// Generics with interface
interface UserInterface<T, V> {
name: string;
data: T;
info: V;
}
const user1: UserInterface<{meta: string}, string> = {
name: 'foo',
data: {
meta: 'bar',
},
info: 'hello',
};
# Enum
- Recommend - Use for constants in application
// Enums
// Alternatives is to use Union of strings like 'On'|'Off'
enum StatusEnum {
On, // can be capital letters too
Off,
Loading = 'Pending', // equal not colon (:)
}
// let foo: StatusEnum = 'On'; // not assignable
let foo: StatusEnum = StatusEnum.On;
console.log(StatusEnum.On); // 0
console.log(StatusEnum.Off); // 1
console.log(StatusEnum.Loading); // Pending
It is common to use Enums inside Interfaces
interface UserInterface {
name: string;
status: StatusEnum;
}