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

wejs22.pdf

 wejs22.pdf

8ad58ff2bfccf7b4c07b34000c1d6afd?s=128

Kodai Nakamura

July 23, 2018
Tweet

Transcript

  1. ©2018 Wantedly, Inc. Practical Typed React App We Are JavaScripters!

    @22nd 23.July.2018 - Kodai Nakamura
  2. ©2018 Wantedly, Inc. Practical Typed React App We Are JavaScripters!

    @22nd 23.July.2018 - Kodai Nakamura
  3. ©2018 Wantedly, Inc. Kodai Nakamura Github: @kdnk Twitter: @kdnk__ Engineer

    at Wantedly, inc. ৽ଔ1೥໨ JavaScript, TypeScript, React, Rails, Ruby
  4. ©2018 Wantedly, Inc. ձࣾϖʔδϦχϡʔΞϧ ‣ TypeScriptಋೖ ‣ React / Redux

    ͳWebΞϓϦ #BDLHSPVOE
  5. ©2018 Wantedly, Inc. $PNQPOFOUͷܕఆٛΛͲ͏͢Δ͔

  6. ©2018 Wantedly, Inc. ‣ ϖʔδ͝ͱʹඞཁͱͳΔϑΟʔϧυ͸ҧ͏ - ͋ΔϖʔδͰ͸company.name͚ͩɺผͷϖʔδͰ͸company.url΋ཉ͍͠ͱ͔ ‣ ϖʔδ͝ͱʹඞཁͳϑΟʔϧυͷΈΛฦ͢API͕͋Δ ‣

    Container, ComponentΛෳ਺ͷϖʔδͰ࢖͍ճ͍ͨ͠ ‣ RailsͷmodelʹରԠ͢ΔܕΛWtdModelsͱͯ͠ఆٛ લఏ ϖʔδ͝ͱʹܕఆ͕ٛҰͭͩͱContainer, Component͸࢖͍ճͤͳ͍ Container, ComponentͰຊ౰ʹඞཁͳ΋ͷ͚ͩΛఆ͍ٛͨ͠
  7. ©2018 Wantedly, Inc. 8UE.PEFMT ‣ API͸active_model_serializersʹґଘ - SerializerʹରԠͨ͠ܕΛఆٛ υϝΠϯ಺Ͱڞ௨ͷܕΛఆٛ declare

    namespace WtdModels { export interface Company { id: number; name: string; // ... projects: HasMany<Project>; } } declare namespace WtdModels { export interface Post { id: number; category_cd: number; title: string | null; created_at: Date | null; published_at: Date | null; // ... liked_status: HasOne<LikedStatus>; tagged_users: HasMany<User>; } }
  8. ©2018 Wantedly, Inc. 8UE.PEFMT ‣ API͸active_model_serializersʹґଘ - SerializerʹରԠͨ͠ܕΛఆٛ declare namespace

    WtdModels { export interface Company { id: number; name: string; // ... projects: HasMany<Project>; } } declare namespace WtdModels { export interface Post { id: number; category_cd: number; title: string | null; created_at: Date | null; published_at: Date | null; // ... liked_status: HasOne<LikedStatus>; tagged_users: HasMany<User>; } } υϝΠϯͰڞ௨ͷܕΛఆٛ
  9. ©2018 Wantedly, Inc. 8UE.PEFMT ‣ API͸active_model_serializersʹґଘ - SerializerʹରԠͨ͠ܕΛఆٛ υϝΠϯͰڞ௨ͷܕΛఆٛ declare

    namespace WtdModels { export interface Company { id: number; name: string; // ... projects: HasMany<Project>; } } declare namespace WtdModels { export interface Post { id: number; category_cd: number; title: string | null; created_at: Date | null; published_at: Date | null; // ... liked_status: HasOne<LikedStatus>; tagged_users: HasMany<User>; } } 3BJMTͷ4FSJBMJ[FSʹఆٛ͞Ε͍ͯΔ΋ͷʹରԠ͍ͯ͠Δ
  10. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ4UBUFͷܕఆٛ interface MappedProps { company?: Company;

    avatar?: Image; background?: Image; // ... isMember: boolean; } function mapStateToProps(state: RootState): MappedProps { return { company: state.companies.common.draftCompany, avatar: state.companies.common.draftCompanyAvatar, // ... isMember: isMemberSelector(state), }; }
  11. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ4UBUFͷܕఆٛ interface MappedProps { company?: Company;

    avatar?: Image; background?: Image; // ... isMember: boolean; } function mapStateToProps(state: RootState): MappedProps { return { company: state.companies.common.draftCompany, avatar: state.companies.common.draftCompanyAvatar, // ... isMember: isMemberSelector(state), }; }
  12. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ"DUJPOͷܕఆٛ interface MappedActions { editModeStarted: typeof

    editModeStarted; editModeFinished: typeof editModeFinished; // ... pushState: typeof pushState; } function mapDispatchToProps(dispatch: Dispatch<RootState>): MappedActions { return bindActionCreators( { editModeStarted, editModeFinished, // ... pushState, }, dispatch ); }
  13. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ"DUJPOͷܕఆٛ interface MappedActions { editModeStarted: typeof

    editModeStarted; editModeFinished: typeof editModeFinished; // ... pushState: typeof pushState; } function mapDispatchToProps(dispatch: Dispatch<RootState>): MappedActions { return bindActionCreators( { editModeStarted, editModeFinished, // ... pushState, }, dispatch ); }
  14. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ"DUJPOͷܕఆٛ interface MappedActions { editModeStarted: typeof

    editModeStarted; editModeFinished: typeof editModeFinished; // ... pushState: typeof pushState; } function mapDispatchToProps(dispatch: Dispatch<RootState>): MappedActions { return bindActionCreators( { editModeStarted, editModeFinished, // ... pushState, }, dispatch ); } $POUBJOFS͝ͱʹ4UBUF "DUJPOͷܕΛఆٛ
  15. ©2018 Wantedly, Inc. ͸͡Ίʹͨ͜͠ͱ $POUBJOFSͰͷ"DUJPOͷܕఆٛ interface MappedActions { editModeStarted: typeof

    editModeStarted; editModeFinished: typeof editModeFinished; // ... pushState: typeof pushState; } function mapDispatchToProps(dispatch: Dispatch<RootState>): MappedActions { return bindActionCreators( { editModeStarted, editModeFinished, // ... pushState, }, dispatch ); } *OUFSGBDFͷఆٛ͸4UBUF "DUJPOͱಉ͡ $POUBJOFSΛ࡞Δͨͼʹ͜ΕΛ΍Δͷ͸ͭΒ͍
  16. ©2018 Wantedly, Inc. $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ declare namespace WtdModels {

    export interface Company { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } } export type Company = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >;
  17. ©2018 Wantedly, Inc. $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company

    = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; declare namespace WtdModels { export interface Company { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } }
  18. ©2018 Wantedly, Inc. $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company

    = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; declare namespace WtdModels { export interface Company { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } }
  19. ©2018 Wantedly, Inc. declare namespace WtdModels { export interface Company

    { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } } $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; υϝΠϯͰڞ௨ͷܕ
  20. ©2018 Wantedly, Inc. $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company

    = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; $PNQPOFOUʹඞཁͳϑΟʔϧυΛ͔͘ declare namespace WtdModels { export interface Company { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } }
  21. ©2018 Wantedly, Inc. declare namespace WtdModels { export interface Company

    { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } } $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; ͜ΕΛ$PNQPOFOU͝ͱʹ͔͘ ͦ͏͢Ε͹ɺ$PNQBOZ͸$PNQPOFOUͰ࢖͏ϑΟʔϧυͷΈͷܕʹͳΔ
  22. ©2018 Wantedly, Inc. declare namespace WtdModels { export interface Company

    { id: number; name: string; company_name: string; // ... projects: HasMany<Project>; } } $PNQBOZEUT ͸͡Ίʹͨ͜͠ͱ $PNQPOFOUͰͷ1SPQTͷܕఆٛ 8UE.PEFMT1BSUJBM͸5ZQF4DSJQUͷ1JDLͷΑ͏ͳ΋ͷ export type Company = WtdModels.Partial< WtdModels.Company, "company_name" | "background" | "name" | "short_location" | "mission_statement", { avatar: WtdModels.HasOne<Image>; } >; ͜ͷఆٛΛ͢΂ͯͷ$PNQPOFOUʹॻ͘ͷ͸ͭΒ͍ $PNQPOFOUʹͲͷϑΟʔϧυ͕ඞཁ͔ௐ΂Δͷ΋ͭΒ͍
  23. ©2018 Wantedly, Inc. ܕͷఆٛΛָʹ͍ͨ͠

  24. ©2018 Wantedly, Inc. վྑ൛ ‣ infer - TypeScript2.8Ͱೖͬͨ - Conditional

    TypeͰਪ࿦͞ΕͨܕΛ ܕͷύϥϝλͱͯ͠ར༻Ͱ͖Δ *OGFSSJOHXJUIJO$POEJUJPOBM5ZQFT JOGFS type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; type FirstArg<T> = T extends (a1: infer A1, ...rest: any[]) => any ? A1 : never;
  25. ©2018 Wantedly, Inc. վྑ൛ ‣ infer - TypeScript2.8Ͱೖͬͨ - Conditional

    TypeͰਪ࿦͞ΕͨܕΛ ܕͷύϥϝλͱͯ͠ར༻Ͱ͖Δ *OGFSSJOHXJUIJO$POEJUJPOBM5ZQFT JOGFS type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; type FirstArg<T> = T extends (a1: infer A1, ...rest: any[]) => any ? A1 : never;
  26. ©2018 Wantedly, Inc. վྑ൛ ‣ infer - TypeScript2.8Ͱೖͬͨ - Conditional

    TypeͰਪ࿦͞ΕͨܕΛ ܕͷύϥϝλͱͯ͠ར༻Ͱ͖Δ *OGFSSJOHXJUIJO$POEJUJPOBM5ZQFT JOGFS type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; type FirstArg<T> = T extends (a1: infer A1, ...rest: any[]) => any ? A1 : never;
  27. ©2018 Wantedly, Inc. վྑ൛ 4UBUF "DUJPOͰͷܕఆٛ function mapStateToProps(state: RootState): MappedProps

    { return { company: state.companies.common.draftCompany, avatar: state.companies.common.draftCompanyAvatar, // ... isMember: isMemberSelector(state), }; } interface MappedProps { company?: Company; avatar?: Image; background?: Image; // ... isMember: boolean; }
  28. ©2018 Wantedly, Inc. վྑ൛ 4UBUF "DUJPOͰͷܕఆٛ function mapStateToProps(state: RootState): MappedProps

    { return { company: state.companies.common.draftCompany, avatar: state.companies.common.draftCompanyAvatar, // ... isMember: isMemberSelector(state), }; } ͜ͷؔ਺ఆٛʹରͯ͠ʜ
  29. ©2018 Wantedly, Inc. վྑ൛ 4UBUF "DUJPOͰͷܕఆٛ function mapStateToProps(state: RootState): MappedProps

    { return { company: state.companies.common.draftCompany, avatar: state.companies.common.draftCompanyAvatar, // ... isMember: isMemberSelector(state), }; } type Props = OwnProps & ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps>; ͜Ε͚ͩͰΑ͘ͳΔ
  30. ©2018 Wantedly, Inc. վྑ൛ 8UE.PEFMT6OJPO 1SPQTͰͷܕఆٛ ‣ Union - جຊతʹ͸&ͱಉ͡

    - [ComponentName]ModelsΛ ֤ComponentͰఆٛ - ਌ComponentͰimportͯ͠ Union // CompanyCardLateral.tsx export interface CompanyCardLateralModels { Company: Company; } import CompanyCard, { CompanyCardModels } from "./CompanyCard"; import CompanyCardLateral, { CompanyCardLateralModels } from "./CompanyCardLateral"; type Company = WtdModels.UnionAll< WtdModels.Partial<WtdModels.Company, "id">, CompanyCardModels["Company"], CompanyCardLateralModels["Company"] >;
  31. ©2018 Wantedly, Inc. վྑ൛ 8UE.PEFMT6OJPO 1SPQTͰͷܕఆٛ ‣ Union - جຊతʹ͸&ͱಉ͡

    - [ComponentName]ModelsΛ ֤ComponentͰఆٛ - ਌ComponentͰimportͯ͠ Union // CompanyCardLateral.tsx export interface CompanyCardLateralModels { Company: Company; } import CompanyCard, { CompanyCardModels } from "./CompanyCard"; import CompanyCardLateral, { CompanyCardLateralModels } from "./CompanyCardLateral"; type Company = WtdModels.UnionAll< WtdModels.Partial<WtdModels.Company, "id">, CompanyCardModels["Company"], CompanyCardLateralModels["Company"] >; ࢠ$PNQPOFOUͰ.PEFMTΛఆٛ
  32. ©2018 Wantedly, Inc. վྑ൛ 8UE.PEFMT6OJPO 1SPQTͰͷܕఆٛ ‣ Union - جຊతʹ͸&ͱಉ͡

    - [ComponentName]ModelsΛ ֤ComponentͰఆٛ - ਌ComponentͰimportͯ͠ Union // CompanyCardLateral.tsx export interface CompanyCardLateralModels { Company: Company; } import CompanyCard, { CompanyCardModels } from "./CompanyCard"; import CompanyCardLateral, { CompanyCardLateralModels } from "./CompanyCardLateral"; type Company = WtdModels.UnionAll< WtdModels.Partial<WtdModels.Company, "id">, CompanyCardModels["Company"], CompanyCardLateralModels["Company"] >; ਌$PNQPOFOUͰJNQPSU
  33. ©2018 Wantedly, Inc. վྑ൛ 8UE.PEFMT6OJPO 1SPQTͰͷܕఆٛ ‣ Union - جຊతʹ͸&ͱಉ͡

    - [ComponentName]ModelsΛ ֤ComponentͰఆٛ - ਌ComponentͰimportͯ͠ Union // CompanyCardLateral.tsx export interface CompanyCardLateralModels { Company: Company; } import CompanyCard, { CompanyCardModels } from "./CompanyCard"; import CompanyCardLateral, { CompanyCardLateralModels } from "./CompanyCardLateral"; type Company = WtdModels.UnionAll< WtdModels.Partial<WtdModels.Company, "id">, CompanyCardModels["Company"], CompanyCardLateralModels["Company"] >; 6OJPO
  34. ©2018 Wantedly, Inc. ·ͱΊ

  35. ©2018 Wantedly, Inc. ·ͱΊ ‣ infer ศར ‣ ܕఆٛ͸ͳΔ΂ָ͘ʹ