• [TypeScript] Model a DataStore type


    Given this code as starter:

    export interface DataEntity {
      id: string
    }
    export interface Movie extends DataEntity {
      director: string
    }
    export interface Song extends DataEntity {
      singer: string
    }
     
    export type DataEntityMap = {
      movie: Movie
      song: Song
    }
     
    export class DataStore {}

    This DataEntityMap object should drive a lot of what happens to DataStore.

    Ultimately, DataStore should end up with methods like

    const ds = new DataStore()
    ds.addSong({ id: "song-123", singer: "The Flaming Lips" })
    ds.addMovie({
      id: "movie-456",
      director: "Stephen Spielberg",
    })
    ds.getSong("song-123") // returns the song
    ds.getMovie("movie-456") // returns the movie
    ds.getAllSongs() // array of all songs
    ds.getAllMovies() // array of all movies
    ds.clearSongs() // clears all songs
    ds.clearMovies() // clears all movies

    It’s ok to define these explicitly in the DataStore class, but they should be type-checked against the DataEntityMap type in some way.

    Requirements

    • If you mis-name a method on the class (e.g., getSongs instead of getAllSongs), you should get some sort of type error that alerts you that you’ve broken the established pattern
    • If you add a new entity like Comic (shown below) and make no other changes to your solution, you should get some sort of type error that alerts you to the absence of a clearComicsgetAllComics and getAllSongs method.

    • There should be no externally-visible properties on an instance of DataStore beyond the required methods
    • Your code, and the test suite should type-check

    .

    .

    .

    .

    .

    .

    .

    .

    Answer

    export interface DataEntity {
      id: string
    }
    export interface Movie extends DataEntity {
      director: string
    }
    export interface Song extends DataEntity {
      singer: string
    }
    
    export interface Comic extends DataEntity {
      issueNumber: number
    }
    
    export type DataEntityMap = {
      movie: Movie
      song: Song
    }
    
    /**
     * if you change DataEntityMap from type to interface
     * Then you can have the DataEntityMap defined in multi files and TS will combine those automaticlly
    // model/song.model.ts
    export interface DataEntityMap {
      song: Song;
    }  
    // model/movie.model.ts
    export interface DataEntityMap {
      movie: Movie;
    }
     */
    
    export type DataStoreMethods = {
      [K in keyof DataEntityMap as `getAll${Capitalize<K>}s`]: () => DataEntityMap[K][]
    } & {
      [K in keyof DataEntityMap as `get${Capitalize<K>}`]: (id: string) => DataEntityMap[K]
    } & {
      [K in keyof DataEntityMap as `clear${Capitalize<K>}s`]: () => void
    }
    & {
      [K in keyof DataEntityMap as `add${Capitalize<K>}`]: (item: DataEntityMap[K]) => DataEntityMap[K]
    }
    
    function isDefined<T>(x: T | undefined): x is T {
      return typeof x !== "undefined";
    }
    
    export class DataStore implements DataStoreMethods {
      #data: {[K in keyof DataEntityMap]: Record<string, DataEntityMap[K]>} = {
        movie: {},
        song: {}
      }
    
      getSong(id: string): Song {
        const song =  this.#data.song[id];
        if (!song) {
          throw new Error(`Could not find a song with id ${id}`);
        }
        return song;
      }
      getAllSongs(): Song[] {
        return Object.keys(this.#data.song).map(id => this.#data.song[id]).filter(isDefined)
      }
      clearSongs(): void {
        this.#data.song = {}
      }
    
      addSong(song: Song) {
        this.#data.song[song.id] = song;
        return song;
      }
    
      getMovie(id: string): Movie {
        const movie =  this.#data.movie[id];
        if (!movie) {
          throw new Error(`Could not find a movie with id ${id}`);
        }
        return movie;
      }
      getAllMovies(): Movie[] {
        return Object.keys(this.#data.movie).map(id => this.#data.movie[id]).filter(isDefined)
      }
      clearMovies(): void {
        this.#data.movie = {}
      }
      addMoive(movie: Movie) {
        this.#data.movie[movie.id] = movie;
        return movie;
      }
    }
  • 相关阅读:
    计算机入门知识
    iOS学习之-开机引导图
    学习笔记之09-空指针和野指针
    学习笔记之08-self关键字
    学习笔记之07-自定义构造方法和description方法
    学习笔记之06-点语法
    学习笔记之05-第一个OC的类
    学习笔记之04-第一个OC程序解析
    学习笔记之03-第一个OC程序
    hdoj1016 [dfs]
  • 原文地址:https://www.cnblogs.com/Answer1215/p/16475167.html
Copyright © 2020-2023  润新知