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
1.5k views
in Technique[技术] by (71.8m points)

javascript - Typescript error:Type 'number' is not assignable to type 'never'

interface Opts {
  onFrame: () => void;
  onAudioSample: null;
  emulateSound: boolean;
  sampleRate: number;
}

class NES {
    constructor(opts: Opts) {
        this.opts = {
            onFrame() { },
            onAudioSample: null,
            emulateSound: true,
            sampleRate: 44100,
        }

        if (typeof opts !== "undefined") {
            let key: keyof Opts
            for (key in this.opts) {
                if (typeof opts[key] !== "undefined") {
                    // got err here
                    this.opts[key] = opts[key];
                }
            }
        }
    }
    opts: Opts
}

you can cheak the error on TS playground:here

typescript: v3.8.3 err: Type 'number' is not assignable to type never. I don't understand why it is a never type.

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

You are getting that error because TypeScript can't infer that this.opts[key] and opts[key] are the same type. If you were to cover up each half of the =:

  • opts[key] could be a Function, null, boolean, or number
  • this.opts[key] needs to receive a Function, null, boolean, or number depending on the value of key, which we don't know
  • the only supertype in common for Function, null, boolean, and number is never, so that's the type that TypeScript wants for this.opts[key]

Interestingly, if you were to extract this to an anonymous generic function, it works: Within a single assignment Typescript can infer and use the type Opts[K]. jcalz suggests a similar solution in this similar question.

if (typeof opts[key] !== "undefined") {
  // this.opts[key] = opts[key];
  (<K extends keyof Opts>(k: K) => { this.opts[k] = opts[k]; })(key);
}

typescript playground

That said, I would use the spread operator as in Mukesh Soni's answer, ending your assignment of this.opts with ...opts, or use Object.assign. There's a slight risk that the passed opts contains extra keys, but Typescript should ensure otherwise at compile time. (For that matter, if you're expecting opts to be optional and potentially incomplete, it should probably be defined as opts?: Partial<Opts>.)

class NES {
    constructor(opts?: Partial<Opts>) {
        this.opts = Object.assign({
            onFrame() { },
            onAudioSample: null,
            emulateSound: true,
            sampleRate: 44100,
        }, opts);
    }
    opts: Opts
}

See also: Object spread vs. Object.assign, which notes that the solutions are quite similar and both applicable for default options values.


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

1.4m articles

1.4m replys

5 comments

57.0k users

...