Часть II
Но...
let n: number = 42
let s: string = 'Hello, world!'
let a: number[] = [1, 2, 3, 4]
let n = 42
let s = 'Hello, world!'
let a = [1, 2, 3, 4]
🎉
let shapes = [new Circle(), new Square()]
shapes.push(new Triangle())
let shapes = [new Circle(), new Square()]
// Argument of type 'Triangle'
// is not assignable to parameter of type 'Square | Circle'.
shapes.push(new Triangle())
let shapes = [new Circle(), new Square()]
shapes.push(new Triangle())
let shapes = [new Circle(), new Square()]
shapes.push(new Triangle())
let shapes = [new Circle(), new Square()]
shapes.push(new Triangle())
let shapes = [new Circle(), new Square()]
// Argument of type 'Triangle'
// is not assignable to parameter of type 'Square | Circle'.
shapes.push(new Triangle())
let shapes: Shape[] = [new Circle(), new Square()]
shapes.push(new Triangle())
class Human {
name: string
}
class Robot {
name: string
}
let human: Human = new Robot()
🤖
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj as Shape)
}
throw new TypeError('Argument is not instanceof Shape')
}
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj as Shape)
}
throw new TypeError('Argument is not instanceof Shape')
}
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj as Shape)
}
throw new TypeError('Argument is not instanceof Shape')
}
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj as Shape)
}
throw new TypeError('Argument is not instanceof Shape')
}
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj as Shape)
}
throw new TypeError('Argument is not instanceof Shape')
}
function addShape(shapes: Shape[], obj: object) {
if (obj instanceof Shape) {
shapes.push(obj)
}
throw new TypeError('Argument is not instanceof Shape')
}
Чего еще желать?
// String.split
split(separator: ?, limit: number): string[]
// String.split
split(separator: string | RegExp, limit: number): string[]
// String.split
split(separator: string | RegExp, limit: number): string[]
function negate(n: string | number) {
if (typeof n === 'string') {
return '-'.concat(n);
} else {
return -n;
}
}
function negate(n: string | number) {
if (typeof n === 'string') {
return '-'.concat(n);
} else {
return -n;
}
}
function negate(n: string | number) {
if (typeof n === 'string') {
return '-'.concat(n);
} else {
return -n;
}
}
function negate(n: string | number) {
if (typeof n === 'string') {
return '-'.concat(n);
} else {
return -n;
}
}
function negate(n: string | number) {
if (typeof n === 'string') {
return '-'.concat(n);
}
return -n;
}
type Cat = {
purr()
}
type Cat = {
purr()
}
type Dog = {
woof()
}
type Cat = {
purr()
}
type Dog = {
woof()
}
type CatDog = Cat & Dog
// String.split
split(separator: string | RegExp, limit: number): string[]
type StringOrRegExp = string | RegExp
// String.split
split(separator: StringOrRegExp, limit: number): string[]
type Point = {
x: number
y: number
}
interface Point {
x: number
y: number
}
Фух, теперь точно всё...
function get(obj, keyName) {
return obj[keyName]
}
function get(obj: any, keyName: string): any {
return obj[keyName]
}
// TypeError: Cannot read property 'prototype' of null
get(null, 'prototype')
function get(obj, keyName) {
return obj[keyName]
}
function get(obj: any, keyName: string): any {
return obj[keyName]
}
// TypeError: Cannot read property 'prototype' of null
get(null, 'prototype')
function get(obj, keyName) {
return obj[keyName]
}
function get(obj: any, keyName: string): any {
return obj[keyName]
}
// TypeError: Cannot read property 'prototype' of null
get(null, 'prototype')
function get(obj, keyName) {
return obj[keyName]
}
function get(obj: any, keyName: string): any {
return obj[keyName]
}
// TypeError: Cannot read property 'prototype' of null
get(null, 'prototype')
Кажется нам нужен...
function identity(arg: any): any {
return arg;
}
function identity<T>(arg: T): T {
return arg;
}
function identity<T>(arg: T): T {
return arg;
}
identity('string') // T is string
identity(12131415) // T is number
identity([4, 8, 15, 16, 23, 42]) // T is number[]
const fib: Array<number> = [1, 1, 2, 3, 5]
// Argument of type 'string'
// is not assignable to parameter of type 'number'.
fib.push('1')
const map: Map<number, string> = new Map()
// Argument of type 'number'
// is not assignable to parameter of type 'string'.
map.set(1, 1)
interface IStack<TItem> {
push(item: TItem)
pop(): TItem
}
let numStack: IStack<number> = [1, 2, 3]
interface IStack<number> {
push(item: number)
pop(): number
}
let numStack: IStack<number> = [1, 2, 3]
type AsyncResult<TResult> = Promise<TResult> | TResult
let result: AsyncResult<string> = Promise.resolve('200')
let result: AsyncResult<string> = '200'
type AsyncResult<string> = Promise<string> | string
let result: AsyncResult<string> = Promise.resolve('200')
let result: AsyncResult<string> = '200'
class Stack<TItem> implements IStack<TItem> {
private state: TItem[]
constructor() {
this.state = []
}
push(item: TItem) {
this.state.push(item)
}
pop(): TItem {
return this.state.pop()
}
}
class Stack<TItem> implements IStack<TItem> {
private state: TItem[] = []
push(item: TItem) {
this.state.push(item)
}
pop(): TItem {
return this.state.pop()
}
}
interface ISwim {
swim()
}
class Dog implements ISwim {
swim() { ... }
}
class Duck implements ISwim {
swim() { ... }
}
function swimTogether<
T1 implements ISwim,
T2 implements ISwim
>(firstPal: T1, secondPal: T2) {
firstPal.swim()
secondPal.swim()
}
type TypeName<T> =
T extends string ? 'string' :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object'
type TypeName<string> =
string extends string ? 'string' :
T extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object'
type TypeName<number> =
number extends string ? 'string' :
number extends number ? 'number' :
T extends boolean ? 'boolean' :
T extends undefined ? 'undefined' :
T extends Function ? 'function' :
'object'
function get(obj: any, keyName: string): any {
return obj[keyName]
}
function get<T>(obj: T, keyName: string): any {
return obj[keyName]
}
Решение: Lookup Types и keyof
interface IUser {
login: string
age: number
gender: 'male' | 'female'
}
let login: IUser['login']
let login: string
let loginOrAge: IUser['login' | 'age']
let loginOrAge: string | number
interface IUser {
login: string
age: number
gender: 'male' | 'female'
}
let key: keyof IUser
let key: 'login' | 'age' | 'gender'
function get(obj, keyName) {
return obj[keyName]
}
function get<T>(obj: T, keyName: keyof T): T[keyof T] {
return obj[keyName]
}
function get<T>(obj: T, keyName: keyof T): T[keyof T] {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
function get<{ a: 1 }>(obj: T, keyName: keyof T): T[keyof T] {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
function get<{ a: 1 }>(obj: T, keyName: 'a'): T['a'] {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
function get<{ a: 1 }>(obj: T, keyName: 'a'): number {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
function get<T>(obj: T, keyName: keyof T): T[keyof T] {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
// Argument of type '"c"'
// is not assignable to parameter of type '"a" | "b"'.
let c: undefined = get({ a: 1, b: 2 }, 'c')
function get<T, K extends keyof T>(obj: T, keyName: K): T[K] {
return obj[keyName]
}
let a: number = get({ a: 1 }, 'a')
let c: undefined = get({ a: 1, b: 2 }, 'c')
interface IUser {
login: string
age: number
gender: 'male' | 'female'
}
const user = { login: 'dimastark', age: 21, gender: 'male' }
const readonlyUser: ? = Object.freeze(user)
interface IFrozenUser {
readonly login: string
readonly age: number
readonly gender: 'male' | 'female'
}
const user = { login: 'dimastark', age: 21, gender: 'male' }
const readonlyUser: IFrozenUser = Object.freeze(user)
Решение: Mapped Types
interface IUser {
login: string
age: number
gender: 'male' | 'female'
}
type Readonly<T> = {
readonly [P in 'login' | 'age' | 'gender']: T[P];
};
const user = { login: 'dimastark', age: 21, gender: 'male' }
const readonlyUser: Readonly<IUser> = Object.freeze(user)
interface IUser {
login: string
age: number
gender: 'male' | 'female'
}
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
const user = { login: 'dimastark', age: 21, gender: 'male' }
const readonlyUser: Readonly<IUser> = Object.freeze(user)
type ValueOf<T> = T extends {
[key: string]: infer U
} ? U : never;
ValueOf<{ a: string, b: string }> // string
ValueOf<{ a: string, b: number }> // string | number
interface IUser {
login: string
birthDate: {
year: number
month: number
day: number
}
gender: 'male' | 'female'
}
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};
type DeepReadonly<T> = {
[P in keyof T]:
T[P] extends (infer U)[] ? DeepReadonly<U>[] :
T[P] extends object ? DeepReadonly<T[P]> :
readonly T[P];
};