Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ts-dwx-19

 ts-dwx-19

Gregor Woiwode

June 26, 2019
Tweet

More Decks by Gregor Woiwode

Other Decks in Programming

Transcript

  1. Conditional types add ternery expressions I N T R O

    D U C T I O N declare type StringOrNull<T> = T extends string ? string : null;
  2. Benefit I N T R O D U C T

    I O N More flexible type system Better to maintain
  3. How to read the syntax I N T R O

    D U C T I O N declare type StringOrNull<T> = T extends string ? string : null; I f t h e g i v e n t y p e T i s a s t r i n g . . . . . . t h a n re t u r n t h e t y p e s t r i n g . . . o t h e r w i s e re t u r n t h e t y p e n u l l .
  4. How to inspect conditional types D E B U G

    G I N G Since we add logic specifying types more precisely, we need to test it.
  5. Fill in the gaps D E B U G G

    I N G declare type StringOrNull<T> = T extends !... declare type isString = StringOrNull<string>;
  6. Observation D E B U G G I N G

    declare type isString = StringOrNull<string | number>; type isStringOrNumber = string | null #
  7. Learning D E B U G G I N G

    $ Unwanted types need to be omitted explicitly.
  8. Nested ternary expressions CO N D I T I O

    N A L T Y P E S declare type StringOrNull<T> = T extends string ? string : T extends null ? null : never; . . . o t h e r w i s e i f T i s o f t y p e n u l l . . . r e t u r n t y p e n u l l . . . o t h e r w i s e re t u r n t y p e n ev e r
  9. Error handling for types N E V E R T

    Y P E % The never type represents the type of values that never occur. https://www.typescriptlang.org/docs/handbook/basic-types.html
  10. Examples N E V E R T Y P E

    function error( message: string ): never { throw new Error(message); } function infiniteLoop(): never { while (true) { } } Th rowi n g Error s I n fi n i t e Loop
  11. Congratulations! C O N D I T I O N

    A L T Y P E S Now, you are familiar with the syntax of conditional types. Now, we will have a look to apply this knowledge in practice.
  12. Look inside structures inferring types C O N D I

    T I O N A L T Y P E S type Foo<T> = T extends { a: infer U } ? U : never; I f t h e g i v e n t y p e T h a s t h e p r o p e r t y a n o t i c e i s t t y p e a n d r e t u r n i t .
  13. No Redux knowledge needed D I S C L A

    I M E R No worries, we will continue focusing on conditional types.
  14. No Redux bashing D I S C L A I

    M E R We just have a look at what can be improved. This talk will not mention all the cool benefits coming with Redux.
  15. Before centralized state management... I N F E R T

    Y P E S CO N D I T I O N A L LY export class RootComponent { notes$: Observable<Notes[]>; constructor(private notes: NotesService) { this.notes$ = this.notes.loadNotes(); } }
  16. Interacting with the Store is hard I N F E

    R T Y P E S C O N D I T I O N A L L Y export class RootComponent implements OnInit { constructor(private store: Store<fromNotes.NotesState>) {} ngOnInit() { this.store.dispatch(new LoadNotes()); } } From where do I need to import the state? From where do I need to import the action? Why am I not receiving a return value?
  17. Actions need to be maintained I N F E R

    T Y P E S C O N D I T I O N A L L Y export class LoadNotes implements Action { readonly type = NotesActionTypes.LoadNotes; } export class LoadNotesSuccess implements Action { readonly type = NotesActionTypes.LoadNotesSuccess; constructor(public payload: Note[]) {} }
  18. An action is process by a reducer function I N

    F E R T Y P E S CO N D I T I O N A L LY switch (action.type) { case NotesActionTypes.LoadNotesSuccess: return setNotes(action.payload, slice); !!... function setNotes(notes: Note[], slice: NotesSlice): NotesSlice { return { !!...slice, entities: notes }; } Case Reducer
  19. Wouldn‘t it be nice, if ...? I N F E

    R T Y P E S C O N D I T I O N A L L Y export class RootComponent implements OnInit { notes$: Observable<Note[]>; constructor(private notesFacade: StoreFacade) { this.notes$ = this.notesFacade.all$; } ngOnInit() { this.notesFacade.loadNotes(); } } Creates Action + Dispatches Action Is created dynamically Offers consumable selectors
  20. What needs to be done? I N F E R

    T Y P E S C O N D I T I O N A L L Y Action Type Case Reducer Self Dispatching Action (payload: P) => void | () => void Case Reducer
  21. Low hanging fruit | Automating reducer generation I N F

    E R T Y P E S C O N D I T I O N A L L Y Self Dispatching Action Self Dispatching Action Self Dispatching Action Self Dispatching Action Reducer C o m b i n i n g a ct i o n t y p e & c a s e re d uc e r b u i l d i n g t h e red u cer fu n ct i o n .
  22. The case reducer challange I N F E R T

    Y P E S CO N D I T I O N A L LY function caseReducerA<T, P>(state: T, payload: P): T { !!... } function caseReducerB<T, Q>(state: T, payload: Q): T { !!... } function caseReducerC<T>(state: T): T { !!... } Or ... Or ...
  23. Self dispatching action I N F E R T Y

    P E S C O N D I T I O N A L L Y Type Case Reducer
  24. Learning I N F E R T extends (state: any,

    payload: infer TPayload) !=> any ? (payload: TPayload) !=> void : never; i n f e r l e t s y o u ex t ra c t a t y p e b a s e d o n t h e u s a g e o f t h e re s p e c t i v e m e t h o d
  25. Congratulations! C O N D I T I O N

    A L T Y P E S Now, you can handle more advanced challenges using conditional types.
  26. NgRx Ducks C O N D I T I O

    N A L T Y P E S @Ducksify({ initialState: !!... }) export class NoteDucks { loadAll = effect('Load Notes‘); @Action('Loading Notes succeeded') set(State: State, notes: Note[]) { return { !!...state, entities: notes }; } Case Reducer Type @Component({ !!... }) export class RootComponent implements OnInit { constructor(@Inject(NoteDucks) private ducks: Duck<NoteDucks>) {} ngOnInit() { this.ducks.loadAll.dispatch(); } }
  27. Predefined helper types I N F E R T Y

    P E S CO N D I T I O N A L LY Exclude<T, U> Exclude from T those types that are assignable to U. Extract<T, U> Extract from T those types that are assignable to U. NonNullable<T> Exclude null and undefined from T. ReturnType<T> Obtain the return type of a function type. InstanceType<T> Obtain the instance type of a constructor function type. ConstructorParameters<T> Obtain the parameter types of a constructor function type. https://www.typescriptlang.org/docs/handbook/advanced-types.html
  28. Recapitulation THE END Conditional Types are ternary expressions Conditional Types

    can be nested Nested types can be extracted with infer Conditional Types add more flexibility Automated tests can be done with ts-snippet
  29. medium.com/@gregor.woiwode @GregOnNet co-IT.eu GmbH Inspire to change Thank you for

    listening. http://speakerdeck.com/gregonnet/ts-dwx-19
  30. Further Reading R E S O U R C E

    S Conditional types in TypeScript - Artsy Engineering TypeScript 2.8: Conditional Types — Marius Schulz Notes on TypeScript: Conditional Types - DEV Community *+ Conditional types in TypeScript – JavaScript everyday – Medium TypeScript: Create a condition-based subset types – DailyJS – Medium A Look at TypeScript’s Conditional Types TypeScript conditional types real-life example - codewithstyle.info https://www.reddit.com/r/typescript/comments/9n189u/how_are_you_using_conditional_types/