Einfache TypeScript-Tricks, um Ihre Anwendungen unendlich zu skalieren

Wir verwenden TypeScript, weil es die Entwicklung sicherer und schneller macht.

Aber meiner Meinung nach enthÀlt TypeScript sofort zu viele AblÀsse. Sie helfen JavaScript-Entwicklern beim Wechsel zu TS ein wenig Zeit zu sparen, verbrauchen aber auf lange Sicht viel Zeit.

Ich habe eine Reihe von Einstellungen und Richtlinien fĂŒr eine strengere Verwendung von TypeScript zusammengestellt. Sie mĂŒssen sich einmal an sie gewöhnen - und sie werden in Zukunft viel Zeit sparen.

irgendein

Die einfachste Regel, die meinem Team auf lange Sicht viel Gewinn bringt: 

Verwenden Sie keine.

Es gibt praktisch keine Situationen, in denen Sie einen Typ nicht beschreiben können, anstatt einen zu verwenden. Wenn ich mich in einer Situation befinde, in der ich in einem langfristigen Projekt etwas schreiben muss, finde ich normalerweise Probleme in der Architektur oder im Legacy-Code.

Verwenden Sie generische Typen , Unbekannte oder Überladungen, und Sie können unerwartete Datenfehler vergessen. Solche Probleme sind manchmal schwer zu erkennen und recht teuer zu debuggen.

, 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 , .

Utility Types . .

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, , , , . .




All Articles