«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 Number
Anders 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 = 6
const arg1 = 2, arg2: any = 'foo';
const result1 = service.multiply(arg1, arg2);
// result = NaN
const arg1 = 2, arg2: any = { name: 'foo' };
const result1 = service.multiply(arg1, arg2);
// result = NaN
const arg1 = 9, arg2: any = '9';
const result1 = service.sum(arg1, arg2);
// result = 99
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 {
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 --save
import * as t from 'io-ts'
const User = t.type({
userId: t.number,
name: t.string
})
npm install io-ts
import { 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-transformer
export 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