Explicit generic type argument gets lost when attempting to carry through member expression
See original GitHub issueTypeScript Version: 3.5.3
Search Terms: inference nested member
Code
The Playground link reproduces this issue, but here is the whole code.
// Issue: the generics are not flowing all the way through.
// This works fine
const handler1 = CommandHandler.create<RespondToQuestion>(
requireThat(
isCollaboratorOnRequest()
),
requireThat(
subjectIs(allowedTo.fooTheBar, BasedOnClaims.fromMessageBody(b => b))
),
async ({ body }) => {
console.log(body.subject_id)
return { version: 1 }
}
)
// But when I start chaining the specifications, the type that has been specified to be `RespondToQuestion` is
// now `unknown`.
const handler2 = CommandHandler.create<RespondToQuestion>(
requireThat(
isCollaboratorOnRequest().or(
subjectIs(allowedTo.fooTheBar, BasedOnClaims.fromMessageBody(b => b))
)
),
async ({ body }) => {
console.log(body.subject_id)
return { version: 1 }
}
)
// Specifying the generic seems to do the trick though, but why do I have to? Shouldn't it flow through?
const handler3 = CommandHandler.create<RespondToQuestion>(
requireThat(
isCollaboratorOnRequest<RespondToQuestion>().or(
subjectIs(allowedTo.fooTheBar, BasedOnClaims.fromMessageBody(b => b))
)
),
async ({ body }) => {
console.log(body.subject_id)
return { version: 1 }
}
)
const msg: Message<RespondToQuestion> = { body: { type: 'RespondToQuestion', subject_id: '123' }, meta: null as any }
handler1(msg)
handler2(msg)
handler3(msg)
// Sorry for all the types 😅
export interface AsyncSpecification<T> {
and(other: AsyncSpecification<T>): AsyncSpecification<T>;
or(other: AsyncSpecification<T>): AsyncSpecification<T>;
execute(value: T): Promise<T>;
}
export declare function isCollaboratorOnRequest<T>(): AsyncSpecification<Message<T>>;
export interface Message<T, M = unknown> {
body: T;
meta: M;
}
export interface Claims {
subject_id: string;
}
export type ClaimsLookupStrategy<T> = (message: Message<T>) => Promise<Claims>;
export type AllowedToBasedOnClaims = (claims: Claims) => Promise<Claims>;
export declare function subjectIs<T>(
checkAllowedToBasedOnClaims: AllowedToBasedOnClaims,
claimsLookupStrategy: ClaimsLookupStrategy<T>
): AsyncSpecification<Message<T>>;
export interface AllowedTo {
fooTheBar: AllowedToBasedOnClaims;
}
export declare type Handler<I, O = unknown> = (input: Message<I>) => Promise<O>;
export declare type Pipe<I, O = unknown> = (input: Message<I>, next: Handler<I, O>) => Promise<O>;
export interface CommandResult {
version: number | null;
}
export interface Command { type: string }
export declare const CommandHandler: {
create: <C extends Command>(...pipes: Pipe<C, CommandResult>[]) => Handler<C, CommandResult>;
};
export declare function requireThat<I, O>(specification: AsyncSpecification<Message<I>>): Pipe<I, O>;
export interface RespondToQuestion extends Command {
type: 'RespondToQuestion'
subject_id: string
}
export declare const allowedTo: AllowedTo
export declare type ClaimsWithOptionalSubjectId = Omit<Claims, 'subject_id'> & {
subject_id?: string;
};
export declare const BasedOnClaims: {
fromMessage<T>(messageBodyToClaims: (message: Message<T, unknown>) => ClaimsWithOptionalSubjectId): ClaimsLookupStrategy<T>;
fromMessageBody<T>(messageBodyToClaims: (body: T) => ClaimsWithOptionalSubjectId): ClaimsLookupStrategy<T>;
};
Expected behavior:
The type argument RespondToQuestion
passed to CommandHandler.create<RespondToQuestion>()
should flow all the way through consistently.
Actual behavior:
When using certain patterns, TS will change the type to unknown
.
Additionally, it seems it can’t make up its’ mind. 😅 The error says body
can’t be inferred, and yet the tip gets it right.
Playground Link: Playground
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (3 by maintainers)
Top Results From Across the Web
Try adding an explicit type like 'dynamic', or enable implicit ...
Missing type arguments for generic type 'MaterialPageRoute'. Try adding an explicit type like 'dynamic', or enable implicit-dynamic in your ...
Read more >How To Use Generics in TypeScript - DigitalOcean
In this code, you are creating a new generic type called IsStringType that receives a single type parameter, T . Inside the definition...
Read more >Compiler Error CS0411 - Microsoft Learn
This error occurs if you call a generic method without explicitly providing the type arguments and the compiler cannot infer which type ...
Read more >Function template - cppreference.com
The function parameters that do not participate in template argument deduction (e.g. if the corresponding template arguments are explicitly specified) are ...
Read more >Java Generics FAQs - Under The Hood Of The Compiler
"Unchecked" warnings stem either from using generic types in their raw form or from casts whose target type is a type parameter or...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Your
handler1
working surprises me, honestly.This needs a reasonable-sized repro before we can look at it - once things get this long, 99 times out of 100 it is a problem with the code itself, not TS.