Skip to content

4.1.1-rc strange Type is not assignable to type never with yield & generators #41428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eamodio opened this issue Nov 6, 2020 · 5 comments · Fixed by #51196
Closed

4.1.1-rc strange Type is not assignable to type never with yield & generators #41428

eamodio opened this issue Nov 6, 2020 · 5 comments · Fixed by #51196
Assignees
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@eamodio
Copy link

eamodio commented Nov 6, 2020

TypeScript Version: 4.1.0-beta (4.1.1-rc too)

//cc @mjbvz

Expected behavior:
No error on the following line

const selection = yield step;

As it works fine in TypeScript 4.0.5, and I'm unsure where the never is even coming from. Here is the actual source if it is interesting: https://github.com/eamodio/vscode-gitlens/blob/787bc8f3a976135d51032547e209b93267e14b2f/src%2Fcommands%2FquickCommand.steps.ts#L1794-L1814

Actual behavior:
Error on the line

Type 'QuickPickStep<QuickPickItem>' is not assignable to type 'never'.(2322)

Related Issues:

Code

export enum Directive {
	Back,
	Cancel,
	LoadMore,
	Noop,
}

export namespace Directive {
	export function is<T>(value: Directive | T): value is Directive {
		return typeof value === 'number' && Directive[value] != null;
	}
}

export interface QuickPickItem {
	label: string;
	description?: string;
	detail?: string;
	picked?: boolean;
	alwaysShow?: boolean;
}


export interface QuickInputStep {

	placeholder?: string;
	prompt?: string;
	title?: string;
}

export interface QuickPickStep<T extends QuickPickItem = QuickPickItem> {
	placeholder?: string;
	title?: string;
}

export type StepGenerator =
	| Generator<QuickPickStep | QuickInputStep, StepResult<void | undefined>, any | undefined>
	| AsyncGenerator<QuickPickStep | QuickInputStep, StepResult<void | undefined>, any | undefined>;

export type StepItemType<T> = T extends QuickPickStep<infer U> ? U[] : T extends QuickInputStep ? string : never;
export namespace StepResult {
	export const Break = Symbol('BreakStep');
}
export type StepResult<T> = typeof StepResult.Break | T;
export type StepResultGenerator<T> =
	| Generator<QuickPickStep | QuickInputStep, StepResult<T>, any | undefined>
	| AsyncGenerator<QuickPickStep | QuickInputStep, StepResult<T>, any | undefined>;
export type StepSelection<T> = T extends QuickPickStep<infer U>
	? U[] | Directive
	: T extends QuickInputStep
	? string | Directive
	: never;
export type PartialStepState<T = unknown> = Partial<T> & { counter: number; confirm?: boolean; startingStep?: number };
export type StepState<T = Record<string, unknown>> = T & { counter: number; confirm?: boolean; startingStep?: number };

export function canPickStepContinue<T extends QuickPickStep>(
	_step: T,
	_state: PartialStepState,
	_selection: StepItemType<T> | Directive,
): _selection is StepItemType<T> {
	return false;
}

export function createPickStep<T extends QuickPickItem>(step: QuickPickStep<T>): QuickPickStep<T> {
	return step;
}

export function* showStep<
	State extends PartialStepState & { repo: any },
	Context extends { repos: any[]; title: string; status: any }
>(state: State, _context: Context): StepResultGenerator<QuickPickItem> {
	const step: QuickPickStep<QuickPickItem> = createPickStep<QuickPickItem>({
		title: '',
		placeholder: ''
	});
	const selection: StepSelection<typeof step> = yield step;
	return canPickStepContinue(step, state, selection) ? selection[0] : StepResult.Break;
}
Output
export var Directive;
(function (Directive) {
    Directive[Directive["Back"] = 0] = "Back";
    Directive[Directive["Cancel"] = 1] = "Cancel";
    Directive[Directive["LoadMore"] = 2] = "LoadMore";
    Directive[Directive["Noop"] = 3] = "Noop";
})(Directive || (Directive = {}));
(function (Directive) {
    function is(value) {
        return typeof value === 'number' && Directive[value] != null;
    }
    Directive.is = is;
})(Directive || (Directive = {}));
export var StepResult;
(function (StepResult) {
    StepResult.Break = Symbol('BreakStep');
})(StepResult || (StepResult = {}));
export function canPickStepContinue(_step, _state, _selection) {
    return false;
}
export function createPickStep(step) {
    return step;
}
export function* showStep(state, _context) {
    const step = createPickStep({
        title: '',
        placeholder: ''
    });
    const selection = yield step;
    return canPickStepContinue(step, state, selection) ? selection[0] : StepResult.Break;
}
Compiler Options
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "moduleResolution": 2,
    "target": "ES2019",
    "module": "ESNext"
  }
}

Playground Link: Provided

@mjbvz
Copy link
Contributor

mjbvz commented Nov 9, 2020

Hey @RyanCavanaugh, can someone on the TS team please take a look since this looks like it could be a regression/change in behavior with 4.1

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Nov 12, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.2.0 milestone Nov 12, 2020
@DanielRosenwasser
Copy link
Member

If this is a regression, we should consider whether something will need to be done for a patch release.

@rbuckton
Copy link
Member

The never seems to come from the return type annotation? If I change showStep to explicitly return Generator<QuickPickStep | QuickInputStep, StepResult<QuickPickItem>, any | undefined> instead of the union produced by StepResultGenerator<QuickPickItem>, the error goes away: Playground

I'll have to look into what changed caused this.

@eamodio
Copy link
Author

eamodio commented Jan 14, 2021

@rbuckton Any update on this -- still seeing it with 4.2-beta

@Andarist
Copy link
Contributor

Andarist commented Mar 5, 2023

I updated one of my open PRs to cover for this case as well: #51196

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
8 participants