TypeScriptを使用するのは、開発がより安全かつ迅速になるためです。
しかし、私の意見では、TypeScriptには箱から出してすぐに多くの楽しみが含まれています。これらは、TSに切り替えるときにJavaScript開発者の時間を少し節約するのに役立ちますが、長期的には多くの時間を消費します。
TypeScriptをより厳密に使用するために、一連の設定とガイドラインをまとめました。あなたは一度それらに慣れる必要があります-そしてそれらは将来多くの時間を節約するでしょう。
どれか
私のチームに長期的に多くの利益をもたらす最も単純なルール:
使用しないでください。
タイプを使用する代わりにタイプを記述できない状況は事実上ありません。長期的なプロジェクトで何かを書かなければならない状況に陥った場合、通常、アーキテクチャまたはそのレガシーコードに問題があります。
ジェネリックタイプ、不明、またはオーバーロードを使用すると、予期しないデータエラーを忘れることができます。このような問題は、キャッチするのが難しく、デバッグに非常に費用がかかる場合があります。
, any, — № 3.
strict
TypeScript strict-, , , . TypeScript. , .
strict- undefined is not a function cannot read property X of null. .
-?
, strict .
strict- , . , . , , , .
, — . strict- . . . , . strict-!
, . , @ts-ignore TODO. .
// tsconfig.json file
{
// ...,
"compilerOptions": {
// a set of cool rules
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
// a shortcut enabling 6 rules above
"strict": true,
// ...
}
}
readonly
— readonly.
, , — . , Angular- : , .
? readonly .
?
, , , readonly-.
readonly :
// before
export interface Thing {
data: string;
}
// after
export interface Thing {
readonly data: string;
}
readonly :
// Before
export type UnsafeType = { prop: number };
// After
export type SafeType = Readonly<{ prop: number }>;
readonly , :
// Before
class UnsafeComponent {
loaderShow$ = new BehaviorSubject<boolean>(true);
}
// After
class SafeComponent {
readonly loaderShow$ = new BehaviorSubject<boolean>(true);
}
readonly-:
// Before
const unsafeArray: Array<number> = [1, 2, 3];
const unsafeArrayOtherWay: number[] = [1, 2, 3];
// After
const safeArray: ReadonlyArray<number> = [1, 2, 3];
const safeArrayOtherWay: readonly number[] = [1, 2, 3];
// three levels
const unsafeArray: number[] = [1, 2, 3]; // bad
const safeArray: readonly number[] = [1, 2, 3]; // good
const verySafeTuple: [number, number, number] = [1, 2, 3]; // super
const verySafeTuple: readonly [number, number, number] = [1, 2, 3]; // awesome (after v3.4)
// Map:
// Before
const unsafeMap: Map<string, number> = new Map<string, number>();
// After
const safeMap: ReadonlyMap<string, number> = new Map<string, number>();
// Set:
// Before
const unsafeSet: Set<number> = new Set<number>();
// After
const safeSet: ReadonlySet<number> = new Set<number>();
as const
TypeScript v3.4 const-assertions. , readonly-, . : .
, as const IDE .
Utility Types
TypeScript , .
TypeScript . , .
. , :
( repl.it)
import {Subject} from 'rxjs';
import {filter} from 'rxjs/operators';
interface Data {
readonly greeting: string;
}
const data$$ = new Subject<Data | null>();
/**
* source$ "Observable<Data | null>"
* "null" filter
*
* , TS , .
* "value => !!value" boolean,
*/
const source$ = data$$.pipe(
filter(value => !!value)
)
/**
*
*
* , value Data.
* , "wellTypedSource$"
*/
const wellTypedSource$ = data$$.pipe(
filter((value): value is Data => !!value)
)
// , :)
// source$.subscribe(x => console.log(x.greeting));
wellTypedSource$.subscribe(x => console.log(x.greeting));
data$$.next({ greeting: 'Hi!' });
:
typeof — JavaScript .
instanceof — JavaScript .
is T — TypeScript, . , TS’ .
:
( repl.it)
// typeof narrowing
function getCheckboxState(value: boolean | null): string {
if (typeof value === 'boolean') {
// value has "boolean" only type
return value ? 'checked' : 'not checked';
}
/**
* value “null”
*/
return 'indeterminate';
}
// instanceof narrowing
abstract class AbstractButton {
click(): void { }
}
class Button extends AbstractButton {
click(): void { }
}
class IconButton extends AbstractButton {
icon = 'src/icon';
click(): void { }
}
function getButtonIcon(button: AbstractButton): string | null {
/**
* "instanceof" TS , "icon"
*/
return button instanceof IconButton ? button.icon : null;
}
// is T narrowing
interface User {
readonly id: string;
readonly name: string;
}
function isUser(candidate: unknown): candidate is User {
return (
typeof candidate === "object" &&
typeof candidate.id === "string" &&
typeof candidate.name === "string"
);
}
const someData = { id: '42', name: 'John' };
if (isUser(someData)) {
/**
* TS , someData User
*/
console.log(someData.id, someData.name)
}
, , , . , TypeScript, , , , . .