#Why can't my `KeysOfType<T, LeveledLogMethod>>` be assigned to a `LeveledLogMethod`?

1 messages · Page 1 of 1 (latest)

turbid rivetBOT
#
bawdyinkslinger#0

Preview:```ts
declare class Logger {
silent: boolean
exitOnError: Function | boolean
defaultMeta?: any
clear(): this
close(): this

// for cli and npm levels
error: LeveledLogMethod
warn: LeveledLogMethod
...```

slow hound
#

!ts

turbid rivetBOT
#
declare class Logger {
    silent: boolean;
    exitOnError: Function | boolean;
    defaultMeta?: any;
    clear(): this;
    close(): this;

    // for cli and npm levels
    error: LeveledLogMethod;
    warn: LeveledLogMethod;
    help: LeveledLogMethod;
    data: LeveledLogMethod;
    info: LeveledLogMethod;
    debug: LeveledLogMethod;
    prompt: LeveledLogMethod;
    http: LeveledLogMethod;
    verbose: LeveledLogMethod;
    input: LeveledLogMethod;
    silly: LeveledLogMethod;
}

type LeveledLogMethod = () => string;

type KeysOfType<Obj, Type> = {
    [Prop in keyof Obj]: Obj[Prop] extends Type ? Prop : never
}[keyof Obj]

function validateBeforeCall<T extends Logger, Prop extends KeysOfType<T, LeveledLogMethod>>(logger: T, logFunction: Prop): LeveledLogMethod {
    const x: LeveledLogMethod = logger[logFunction]
//        ^
// Type 'T[Prop]' is not assignable to type 'LeveledLogMethod'.
//   Type 'T[KeysOfType<T, LeveledLogMethod>]' is not assignable to type 'LeveledLogMethod'.
//     Type 'T[T[keyof T] extends LeveledLogMethod ? keyof T : never]' is not assignable to type 'LeveledLogMethod'.
//       Type 'T[keyof T]' is not assignable to type 'LeveledLogMethod'.
//         Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'LeveledLogMethod'.
//           Type 'T[string]' is not assignable to type 'LeveledLogMethod'.
//        ^? - const x: LeveledLogMethod
    
    return () => "hi";
}```
slow hound
#

why can't x be a LeveledLogMethod?

#

hm, I just noticed I can call validateBeforeCall with any key as the second param, that's not working right

vagrant oracle
#

It doesn't solve your problem, but just as a quick note, the Prop generic is not necessary:

- validateBeforeCall<T extends Logger, Prop extends KeysOfType<T, LeveledLogMethod>>(logger: T, logFunction: Prop)
+ validateBeforeCall<T extends Logger>(logger: T, logFunction: KeysOfType<T, LeveledLogMethod>)
#

As a general rule of thumb, a generic type parameter should be used more than once.

slow hound
#

but I don't know why it works

#

and it doesn't compile in the playground, but it does in my ide...

vagrant oracle
#

Run tsc to make sure it's not just your IDE failing to report errors.

turbid rivetBOT
#
bawdyinkslinger#0

Preview:```ts
declare class Logger {
silent: boolean
exitOnError: Function | boolean
defaultMeta?: any
clear(): this
close(): this

// for cli and npm levels
error: LeveledLogMethod
warn: LeveledLogMethod
...```

slow hound
#

I'm not sure why this playground doesn't

#

and I am using 5.2.2

#

I guess I'm okay moving on. Unless, in your opinion, it makes sense that that error should occur

#

oh!

vagrant oracle
#

Is your defaultMeta optional in your local code?

slow hound
#

lol no

#

That's what I was about to say

#

Once I removed it from the example it works the same way as in my IDE

#

wait hold on

#

wtf

#

I misspoke

turbid rivetBOT
#
bawdyinkslinger#0

Preview:```ts
class Logger extends NodeJSStream.Transform {
constructor(options?: LoggerOptions)

silent: boolean
format: logform.Format
levels: Config.AbstractConfigSetLevels
level: string
transports: Transport[]
exceptio

...```

slow hound
#

That is the unmodified class in its declaration file

#

Okay I think I just have a looser tsconfig option

#

in my project

vagrant oracle
#

Btw, the Prop generic type parameter isn't necessary.

slow hound
#

oh yeah, that makes sense

#

Does that make a difference or was it merely unnecessarily verbose?

vagrant oracle
#

Your solution also doesn't do the same thing as the initial question, but well, if that's aceeptable then sure.

slow hound
vagrant oracle
#

No

#

Your initial code works for generic loggers, eg if you make a new logger subclass with a new log level method, you can use that in your initial code.

#

That wouldn't work in your latter code.

slow hound
#

by "wouldn't work", you mean it wouldn't allow me to pass in the subclass's new method?

vagrant oracle
#

Yes.