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.
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 knowFunction
, 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.
I don't know why you are getting that error. One other way to merge both the options might be to use spread operators.
this.opts = {
onFrame() { },
onAudioSample: null,
emulateSound: true,
sampleRate: 44100,
...opts
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With