«The World’s Most Misunderstood Programming Language Has Become the World’s Most Popular Programming Language»
> '5' - 3> '5' + 3
> '5' + - '2'
> 5 + {v: 2}
> 5 - {v: 2}
< 2 // Number < '53' // String< '5-2' // String< '5[object Object]' // String< NaN // NaN NumberAnders Hejlsberg created:
public ngOnInit(): void {
const movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: any): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}public ngOnInit(): void {
const movie = {
title: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: any): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}interface Movie {
name: string;
}
public ngOnInit(): void {
const movie: Movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: Movie): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}interface Movie {
title: string;
}
public ngOnInit(): void {
const movie: Movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: Movie): void {
this.toaster.show(`Today's movie is: ${item.name}`);
}const arg1 = 2, arg2 = 3;
const result1 = service.multiply(arg1, arg2);
// result = 6
const arg1 = 2, arg2: any = '3';
const result1 = service.multiply(arg1, arg2);
// result = 6const arg1 = 2, arg2: any = 'foo';
const result1 = service.multiply(arg1, arg2);
// result = NaNconst arg1 = 2, arg2: any = { name: 'foo' };
const result1 = service.multiply(arg1, arg2);
// result = NaNconst arg1 = 9, arg2: any = '9';
const result1 = service.sum(arg1, arg2);
// result = 99interface Movie {
name: string;
}
public ngOnInit(): void {
const movie: Movie = {
name: 'Game of Thrones',
};
this.showToast(movie);
}
private showToast(item: Movie): void {
this.toaster.show(`Today's movie is: ${item['name']`);
}interface Movie {
name: string;
genre: string;
}
getMovieProp(key: keyof Movie, movie: Movie): string {
return movie[key]?.toString();
}
private showToast(item: Movie): void {
this.toaster.show(getMoviewProp('name'));
}export function* iterableObj() {
yield 1;
yield 'am';
yield 'iterable.';
}export function* iterableObj():
Generator<number, void, void> {
yield 1;
yield 'am';
yield 'iterable.';
}import { select } from 'redux-saga/effects';
// returns ANY object, no checks
const state_0 = yield select(getTaskStatus);
// if Type is specified - TS relyes on it
const state_1: TaskStatus = yield select(getTaskStatus);
// but Type can be specified incorrectly
const state_2: TaskStatus = yield select(getTaskAssignee);import { select } from 'redux-saga/effects';
// returns ANY object, no checks
export function select
<Fn extends (state: any, ...args: any[]) => any>(
selector: Fn,
...args: Tail<Parameters<Fn>>
): SelectEffect// pathOr from Ramda library
export function pathOr<T>(
defaultValue: T, path: Path, obj: any): T;const role = pathOr(null, ['auth', 'user', 'role'], state);
// no compilation errors
const role = pathOr(null, ['auth', 'userrrr', 'role'], state);export function pathOr<T1, T2, T3, R>(
defaultValue: R,
path: [keyof T1, keyof T2, keyof T3],
obj: T1): R;// Typescript
export class SampleService {
public multiply(num: number, num2: number): number {
return num * num2;
}
}
// Javascript
"use strict";
Object.defineProperty(exports, "__esModule",
{ value: true });
class SampleService {
multiply(num, num2) {
return num * num2;
}
}
exports.SampleService = SampleService;multiplyChecked(num: number, num2: number): number {
if (typeof num !== 'number') {
throw Error(`Wrong arg 1: ${typeof num}`)
}
if (typeof num2 !== 'number') {
throw Error(`Wrong arg 2: ${typeof num2}`)
}
return num * num2;
}
@Typed()
public multiplyChecked(num: number, num2: number): number {
return num * num2;
}export function Typed() {
return (target: Object, propertyName: string,
descriptor: TypedPropertyDescriptor<Function>) => {
const method = descriptor.value;
descriptor.value = function() {
checkTypes(target, propertyName, arguments);
return method.apply(this, arguments);
};
};
}import 'reflect-metadata';
function checkTypes(
target: Object, propertyName: string, args: any[]): void {
const paramTypes = Reflect.getMetadata(
'design:paramtypes', target, propertyName);
paramTypes.forEach((param, index) => {
const actualType = typeof arguments[index];
const expectedType =
param instanceof Function ? typeof param() : param.name;
if (actualType !== expectedType) {
throw new Error(`Argument: ${index} of function ${propertyName}
has type: ${actualType} different from
expected type: ${expectedType}.`);
}
});
}__decorate([
src_1.Typed(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Number]),
__metadata("design:returntype", Number)
], TypedTestService.prototype, "multiplyChecked", null);@Typed()
public multiplyChecked(num: number, num2: number): number {
return num * num2;
}npm install ts-stronger-types --saveimport * as t from 'io-ts'
const User = t.type({
userId: t.number,
name: t.string
})
npm install io-tsimport { validate } from "superstruct-ts-transformer";
type User = {
name: string;
alive: boolean;
};
const obj = validate<User>(
JSON.parse('{ "name": "Me", "alive": true }'));
npm install superstruct-ts-transformerexport class Post {
@IsString()
title: string;
@IsInt()
@Min(0)
@Max(10)
rating: number;
@IsEmail()
email: string;
@IsDate()
createDate: Date;
}
validate(obj)
.then(() => {...})
.catch(err => {...})validate(obj)
.then(() => {...})
.catch(err => {...})npm install class-validators --save