# Type Manipulation
# Generic
any
vs<T>
- eg: If we use
any
we don't know the return type of function.
- eg: If we use
- We can't have generic enums and namespaces.
|
|
# Generic type
// Root Generic
function foo<T>(x: T): T {
return x;
}
// Create Non-generic functions - Derived from Root Generic
// - new function with same implementation different types
interface fooInterface<T> {
(x: T): T;
}
let fooNum: fooInterface<number> = foo;
let fooStr: fooInterface<string> = foo;
# Generic Classes
// just like interface
class foo<T> {
factor: T;
result: (x: T) => T;
}
Using above class
|
|
# Generic constraint
- use interface
interface fooInterface {
length: number;
}
function foo<T extends fooInterface>(x: T): T {
return x;
}
# keyof / extends keyof
keyof
gives union of property names of object.keyof extends
is not same asextends
for interface.
// keyof
type Point = {x: number; y: number};
type P = keyof Point; // union x | y
let obj: Point = {x: 3, y: 5};
let key1: P = 'x';
let key2: P = 'y';
// let key3:P = 'z'; // error
// extends keyof
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let user = {
name: 'umesh',
};
let nameValue = getValue(user, 'name'); // umesh
# Indexed access types
type foo = {x: number; y: string};
type fooX = foo['x']; // number
type fooY = foo['y']; // string
type fooXY = foo['x' | 'y']; // number | string
type fooKey = foo[keyof foo]; // same as fooXY ie number | string
# Conditional types
- Mostly Used with Generics
// Ex
interface Y {}
interface X extends Y {}
type s = X extends Y ? string : number; // string
type n = RegExp extends Y ? string : number; // number
// Ex
type c<T> = T extends {length: number} ? T : never;
let obj = {
length: 3,
};
let arr = [3, 4, 5];
let str = 'hello';
let empty = {};
type c1 = c<typeof obj>; // { length: number }
type c2 = c<typeof arr>; // number[]
type c3 = c<typeof str>; // string
type c4 = c<typeof empty>; // never
# Mapped types
type X = {
[prop: string]: string | boolean;
};
let x1: X = {
name: 'umesh', // works
};
let x2: X = {
age: 2, // error,
};
// in keyof
// modifier readonly is optional
type X<T> = {
-readonly [prop in keyof T]: boolean;
};
type Y = {
a: string;
readonly b: number;
};
type XY = X<Y>; // type xy = {a: boolean;b: boolean;}
# Template Literals
type x = "world";
type y = `Hello ${x}`; // `Hello world`
type x = number | string;
type y = `Hello ${x}`; // `Hello ${string}` | `Hello ${number}`
const foo1:y = "Hello"; // error
const foo2:y = "Hello "; // no error
type x = number | string;
type y = "a" | "b";
type z = `${y}_${x}`; // `a_${string}` | `a_${number}` | `b_${string}` | `b_${number}`
# Intrinsic String Manipulation
type x = 'Hello wORLD';
type up = Uppercase<x>; // "HELLO WORLD"
type low = Lowercase<x>; // "hello world"
type cap = Capitalize<x>; // "Hello wORLD"
type uncap = Uncapitalize<x>; // "hello wORLD"