mcclaskc
mcclaskc

Reputation: 167

Typescript compilation errors in weird scenarios

I have a type:

type MyObject = {
    [index:string]: MyObject | Function | "wtf"
}

When I create a variable of this type, it compiles in this basic example:

// compiles
const myObj: MyObject = {
    name: "wtf",
};

As well as with a nested key - note the nested key is notName:, instead of name:

// compiles
const myObj: MyObject = {
    wrapper: {
        notName: "wtf",
    },
};

As soon as I change the nested key to name:, it fails to compile:

/*
Type '{ name: string; }' is not assignable to type 'Function | MyObject | "wtf"'.
  Type '{ name: string; }' is not assignable to type '"wtf"'

*/
const myObj: MyObject = {
    wrapper: {
        name: "wtf",
    },
};

Other weirdness, if I remove Function from the union, it compiles:

type MyObjectNoFunction = {
    [index:string]: MyObjectNoFunction | "wtf"
}

let myObjNoFn: MyObjectNoFunction = {
    wrapper: {
        name: "wtf"
    }
};

Even more weirdness, if I don't include any libs, like es6, in my tsconfig, everything compiles.

tsconfig:

{
  "compilerOptions": {
    "lib": [
      "es6"
    ],
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "strict": true
  }
}

Check out a full example on github

Upvotes: 1

Views: 65

Answers (1)

thedayturns
thedayturns

Reputation: 10823

Not sure exactly what's causing TS to get confused, but here's a wild guess: Maybe this is because Function has a name property in es6, so TypeScript infers that { name: "something" } is an unfinished Function type declaration.

In any case, here are a few ways to fix it.

You can explicitly type the inner object, like this:

type MyObject = {
  [index:string]: MyObject | Function | "wtf"
}

const innerMyObject: MyObject = {
  name: "wtf",
}

const myObj: MyObject = {
  wrapper: innerMyObject,
};

Or you can explicitly type the string literal, like this:

type MyObject = {
  [index:string]: MyObject | Function | "wtf"
}

const myObj: MyObject = {
  wrapper: {
      name: "wtf" as "wtf",
  },
};

Upvotes: 4

Related Questions