Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
630 views
in Technique[技术] by (71.8m points)

dictionary - Typescript Map<enum, set<enum>> "No overload matches this call", but I don't get why?

I am creating a boardgame in Typescript. In it I declare the following:

export enum PieceType {
    PAWN,
    KNIGHT2,
    KNIGHT4,
    WIZARD,
    KING
}

export class Board {
    // ...
    private takeRules: Map<PieceType, Set<PieceType>> = new Map([
        [PieceType.PAWN, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD])],
        [PieceType.KNIGHT2, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KNIGHT4, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KING, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])]
    ]);
    private enchantRules: Map<PieceType, Set<PieceType>> = new Map([
        [PieceType.WIZARD, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])],
        [PieceType.KING, new Set([PieceType.WIZARD])]
    ]);
    // ...
}

This errors as follows:

[tsl] ERROR in ./src/board.ts(28,60)
      TS2769: No overload matches this call.
  Overload 1 of 3, '(iterable: Iterable<readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>]>): Map<PieceType.WIZARD | PieceType.KING, Set<...>>', gave the following error.
    Argument of type '([PieceType.WIZARD, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>] | [PieceType.KING, Set<PieceType.WIZARD>])[]' is not assignable to parameter of type 'Iterable<readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>]>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<[PieceType.WIZARD, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>] | [PieceType.KING, Set<PieceType.WIZARD>], any>' is not assignable to type 'IteratorResult<readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>], any>'.
          Type 'IteratorYieldResult<[PieceType.WIZARD, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>] | [PieceType.KING, Set<PieceType.WIZARD>]>' is not assignable to type 'IteratorResult<readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>], any>'.
            Type 'IteratorYieldResult<[PieceType.WIZARD, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>] | [PieceType.KING, Set<PieceType.WIZARD>]>' is not assignable to type 'IteratorYieldResult<readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>]>'.
              Type '[PieceType.WIZARD, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>] | [PieceType.KING, Set<PieceType.WIZARD>]' is not assignable to type 'readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>]'.
                Type '[PieceType.KING, Set<PieceType.WIZARD>]' is not assignable to type 'readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>]'.
                  Types of property '1' are incompatible.
                    Type 'Set<PieceType.WIZARD>' is not assignable to type 'Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>'.
                      Type 'PieceType.WIZARD' is not assignable to type 'PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4'.
  Overload 2 of 3, '(entries?: readonly (readonly [PieceType.WIZARD | PieceType.KING, Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>])[]): Map<PieceType.WIZARD | PieceType.KING, Set<...>>', gave the following error.
    Type 'Set<PieceType.WIZARD>' is not assignable to type 'Set<PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4>'.

If I put the second map in comments: no problem. If I ommit the wizard enum in the last line of the second map: no problem. I can even put the ommitted value in using the constructor without a problem. E.g.

    private takeRules: Map<PieceType, Set<PieceType>> = new Map([
        [PieceType.PAWN, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD])],
        [PieceType.KNIGHT2, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KNIGHT4, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KING, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])]
    ]);
    private enchantRules: Map<PieceType, Set<PieceType>> = new Map([
        [PieceType.WIZARD, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])],
        [PieceType.KING, new Set([])]
    ]);

   // ...

    constructor() {
        // ...
        this.enchantRules.get(PieceType.KING).add(PieceType.WIZARD)
    }

I really don't understand how this is possible?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Very interesting question. Here is solution:

export enum PieceType {
    PAWN,
    KNIGHT2,
    KNIGHT4,
    WIZARD,
    KING
}

export class Board {
    // ...
    private takeRules = new Map<PieceType, Set<PieceType>>([
        [PieceType.PAWN, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD])],
        [PieceType.KNIGHT2, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KNIGHT4, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4, PieceType.WIZARD, PieceType.KING])],
        [PieceType.KING, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])]
    ]);
    private enchantRules = new Map<PieceType, Set<PieceType>>([
        [PieceType.WIZARD, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])],
        [PieceType.KING, new Set([PieceType.WIZARD])]
    ])
}

I just defined generics for Map instead of defining whole type : new Map<PieceType, Set<PieceType>>.

But main question, why the error occured?

Let's make some analyze of :

   private enchantRules: Map<PieceType, Set<PieceType>> = new Map([
        [PieceType.WIZARD, new Set([PieceType.PAWN, PieceType.KNIGHT2, PieceType.KNIGHT4])],
        [PieceType.KING, new Set([PieceType.WIZARD])]
    ]);

If you put type definition Map<PieceType, Set<PieceType>> before equal sign, TS will try to infer these type. Hence, if you put some PieceType enum value, which don't exists in previous entity, it will throw an error.

Take a look on simplier example:

type Fst = PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4
type Scd = PieceType.WIZARD

let fst: Fst = PieceType.PAWN;
let scd: Scd = PieceType.WIZARD;

scd = fst; // error

You can't assign fst to scd, but, if you add PAWN enum type to Scd type, it will work:

type Fst = PieceType.PAWN | PieceType.KNIGHT2 | PieceType.KNIGHT4
type Scd = PieceType.WIZARD | PieceType.PAWN

let fst: Fst = PieceType.PAWN;
let scd: Scd = PieceType.WIZARD;

scd = fst; // ok

Let's go back to our problem. Because WIZARD was not defined in first Map value V, you are unable to use WIZARD at all.

SO, I believe you should stick with explicit generic type definition instead of defininf your type directly near variable definition.

P.S. You may find this answer also interesting

I'm open to criticizm, so feel free to point my mistakes. Thanks


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...