简体   繁体   中英

How to disable/assert/override inferred types when importing JSON in typescript

I am using the "resolveJsonModule" feature in typescript 2.9 in order to import a json file. Let's say the json file looks like this:

{
  "Nabokov": {
    "Pale Fire": {
      "Pages": "200",
      "Edition": "Paperback",

    },
    "Pnin": {
      "Pages": "150",
      "Edition": "Hardcover"
    },
    "Lolita": {
      "Pages": "150",
      "Edition": "Paperback",
      "Year": "1955"
    }
  },
  "Joyce": {
    "Ulysses": {
      "Pages": "800",
      "Language": "English"
    },
    "Finnegan's Wake": {
      "Pages": "1200",
      "Language": "Gibberish"
    }
  }
}

and i am importing it by:

import catalog from '../resources/catalog.json'

Okay, so when this gets imported, typescript will automatically define types for this. This becomes problematic for me when I am trying to write, for example, a function that can return the info for a author/book.

I want to just do

function getBook(author: string, title: string) {
  return catalog[author][title]
}

I get a "Element implicitly has an 'any' type because expression of type 'string' ..." So it wants me to define author as "Nabokov" | "Joyce" but since the JSON file will be forever expanding, and I don't know what's going to be in it at any time, I want to "genericize" the type for the imported object so that it's just something like [key: string].

Try the following:

type C = typeof catalog;
function getBook<T extends keyof C>(author: T, title: keyof C[T]) {
    return catalog[author][title]
}

getBook("Nabokov", "Lolita"); // OK
getBook("Joyce", "Lolita"); // Not OK

Here is a playground to demonstrate.

Update

Based on your use case, you shouldn't restrict the types of the parameters, and you should just do this:

function getBook(author: string, title: string) {
    try {
        return (catalog as any)[author][title]
    } catch(e) {
        // do error handling here
    }
}

Update 2

The method mentioned above is more or less bypassing TypeScript. If one really want to ensure type-safety, here's the genuine TypeScript approach to do the same thing.

type B = {
    Pages: string;
    Edition?: string;
    Year?: string;
    Language?: string;
};
type C = {
    [index: string]: {
        [index:string]: B
    }
};

function getBook(author: string, title: string): B | undefined {
    const cat: C = catalog;
    if(author in cat && title in cat[author]) {
        return cat[author][title];
    } else {
        // do error handling here
        return undefined;
    }
}

See this playground .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM