Skip to content

Unexpectedly narrow implicit generator typeΒ #63578

Description

@badeball

πŸ”Ž Search Terms

implicit generator union type

πŸ•— Version & Regression Information

I tested this in playground using latest version of the 3rd, 4th, 5th and 6th version lines. The problem is present in all of them.

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.3#code/PQKhCgAIUhJBbADgGwJYGNUBdJYJ6ICmkAzqgOYB2AhlgK4BOxARoQGYD2TkzyH6Aa0hN4HAG6EAJgC4oMOZDZ1K6LKg6VcDahIYlCAMUK1GhAMIALVMkkAKNsfpNL1mZCMnnVmwEppkAHFCSkJtLC4AHgAlOmRiAB9IABl+WnVNRJi4lxtIRIAhakFyBg5lSTzIAGUsQkRKgFEAD2okOJJKgBF+GoZUSnIu2moAFWpeBMgxiaiOAHdK6ezCZGQAGkgxDlRJDeUBSnnKAD4FBQQUDGxcAmIyKk9iajZahh4+QWFCUQkZM+hFMpVOktDpQvoPE5zN47A5Hjk3JDTAi-IFgqFaJEkV5XBstjs9pQDkdTgC5MBwEoVGoNDAsNpdBDHMiYfZmTibP5sdDXD5IABvKCQPCoFYVOFQhEAbnAQuAwEgUW+4mIWCsHV4-AEADohag2JA2fCYdqGLFCHzBZBrcLRTY6QzwYZ2YQsoQjZKTWa4j4ZdaAL7gQOUoE0ygOsF6Z2PN22b2Efxuy1CkVi4TmmV6g1x83aj5pDTJm22tPxvOpMN+yDB636w1l9AwpiUIs2zhvWzoDQkHCN1yQDgGhtN4Kt4up+2gxmu80Izsw31CgNCwPBqnA2lTp1uufxhGJ2cLgUpu0VPcwzO17Pn1za5hFAQlMqUSRjkuT+mR-SFYqlco57ITXvX9n1fKsa0gOsAJ5GxtRIdBgmoPoODfCdJAjacqgQmhkOghE4OwpD1EXZc11DdIMKdH9Hz-F9bGAx8uHKfxqKfcpWzQngH3IJiX0vSDswYnizRfct0ALFtj3HU8uOKXjJDEiTwNlK9DSE+S4NqRASDfdtDS7Sge1ILSBwNdSRIUns6h0qTi3fdCtyjGo6lsKzEBIm1A1I2V1zDSinMI3D4MQ5D-CwkLiNszjgpw9R+KgmKiI4RSw1QmTEuQlL0mUrNDQy9RNOs3SuH07scDc0zSECgq3Jsq07LQ-z9GcxBXK0jzl2XXLXOq5LCBaNpCDqpdFBKzsysgfrWhQYhByqiK+oGmbhrs+ymsIZppriWwpsGjrqxXIMfPIzdP0wrS2rqML2qi9KtPi7M3KywtbOtaKtOeygctUy7EG1SQenpfpyDSsV1u6dBemB37-sBvoBg8iCEo+yRhiWC1XrWxz9E6NHxm2p7UawUZ8YtZSyOpCjscICGoYGWwAchoGBn8WnmZB2600ZunyAew1ufZz7QdyAX4fIT7yeOynTsdKNceJ9GGbxiZWeVn1OZFtXCD5pWFdJoXMc4omSYmCXDu6430dNeYVrbMaDKM0oFjmy39ad23pLB6nZjmON5n2ryDopjdw29+Y-bmfx0Z9jiZKdnWnYN+q3rj+Yza6n7E4Q1YPdGjsHd7FZkEqrOi9zlOvbOp0zCLzsi4Dw7g786ma9WOvVij0nW+QWO02z5Adf7pORs4of80rRupZD9bNsGnalrifxZ+W3vcl2madfXuJh89teF8IdODu6reD+JiYAAljEkUJhYcquox9+ettP0nL+oa+GERlSBMNE-tTPuI+QOCSDwMVfOE0naVT-gAwgQCQFvgrh+WW+hH5Owbt5cA-VEBcBwPgIgkBWK0QqAAXlsuPdI-gUjiQntaAQhA8BzC4G4HsYsqw0HgAmYyrChTX3gn0RAYZ-AsOBlWWq-gmDvw0MgPA1QtIAG0AC6VYdhCPZjKf0MosE4JuPgswHB4AcMoDgUh9VyEaEoRWbKQpahNCwKo7hGjMFNGwQwXBtxIDyxNnESAJihRmMoBY6hVjrTu3EVfKRMjo7zEUeozRzjtF4OIGzMWPiyGWPMckdJX0hQcMkKgUYtwAD89iRFCgMrUIxJSBhVmvmgeA2BQhVN5kGOJLi3H4OXu0VJpismBKUtY6g5ASBhMkZQaRUxBkxKFHQhhTCmlsNaJw4R1SeFDXQPwwRXDSnWhgW-D+xSJkzHmFWGBcC8AjIBmMyJpMfZTNrMwtRLSnFtJ0cQbk3S-G9MyUEjQJzBnDK+KM8ZYxyB3MgMgagAw6CDKWY82h9DGEMAedw607DYUosgLw9ZqABEUK2Ss60fYbDNguRE9wLoERTMcVo1xrzyXGn7L4kJ5oDluirEJIhBzCGgVEb1A54VYocFic8hJ7i3QfOtP4vpNDcD-NJVciZoKlHTIRXM-FzTUWLPmasvhOLNnLI1ZAIlkgSWAsueMncMIwUqPVcKml7TiCWsZbZDloEuXcSIbyha-Lep2vibSxJ1ReoSvBV8qh-SdlyrNWSkFYKZmIuRdsyAaLtXWixRsvFBrRFaQBRI81MiWpgpPrm8JCrOlDWtYmlZ1L-UOtkXUENUrvkRsgPGtVWaVWzKRSMIp106gAGlVXdtuCc-qdjbU8LhsDA5ySk2uwmDOrWyiq3NJrS8wN6Nu6NrDVkqsYhqDIDoOi0pa7RX4KiQsJloafkBObTK-uJagXXImN3St2rT0BvcSC7dN7pXBOTVqid9z32tLPcQcNYZG39E4ZQOg8BWAMCrF2Q98BKAHNg-B0IfqXnX3QBC7gwQ4P1sQIOrtkge34PqgAVQAHL9powAeQAOo0dSQAIio0SQ4cxKBsbWEKMwDGaMjAaAADRGOxvRRix18aFAAQTMCMWAQn2NyZDrJ60DGqMjEEwAWQaOxhjdAsBdg4RpyAgmaMAClaOKeU6x0hbGpMACsTq8f44GIAA

πŸ’» Code

/**
 * Implicit type signature before block removed:
 * 
 * function traverseFeatureChild(featureChild: FeatureChild): Generator<Rule | Location | RuleChild | Background | Step | Examples | DocString | DataTable | TableRow | TableCell, void, unknown>
 * 
 * Implicit type signature after block removed:
 * 
 * function traverseFeatureChild(featureChild: FeatureChild): Generator<FeatureChild, void, unknown>
 * 
 */
function* traverseFeatureChild(featureChild: FeatureChild) {
  yield featureChild;

  // Remove this block.
  if (featureChild.rule) {
    yield* traverseFeatureRule(featureChild.rule);
  }
}

function* traverseFeatureRule(rule: Rule) {
  yield rule;

  if (rule.location) {
    yield rule.location;
  }

  if (rule.children) {
    for (const child of rule.children) {
      yield* traverseRuleChild(child);
    }
  }
}

function* traverseRuleChild(ruleChild: RuleChild) {
  yield ruleChild;

  if (ruleChild.background) {
    yield* traverseBackground(ruleChild.background);
  }

  if (ruleChild.scenario) {
    yield* traverseScenario(ruleChild.scenario);
  }
}

function* traverseBackground(backgorund: Background) {
  yield backgorund;

  if (backgorund.location) {
    yield backgorund.location;
  }

  if (backgorund.steps) {
    for (const step of backgorund.steps) {
      yield* traverseStep(step);
    }
  }
}

function* traverseScenario(scenario: Scenario) {
  yield scenario;

  if (scenario.location) {
    yield scenario.location;
  }

  if (scenario.steps) {
    for (const step of scenario.steps) {
      yield* traverseStep(step);
    }
  }

  if (scenario.examples) {
    for (const example of scenario.examples) {
      yield* traverseExample(example);
    }
  }
}

function* traverseStep(step: Step) {
  yield step;

  if (step.location) {
    yield step.location;
  }

  if (step.docString) {
    yield* traverseDocString(step.docString);
  }

  if (step.dataTable) {
    yield* traverseDataTable(step.dataTable);
  }
}

function* traverseDocString(docString: DocString) {
  yield docString;

  if (docString.location) {
    yield docString.location;
  }
}

function* traverseDataTable(dataTable: DataTable) {
  yield dataTable;

  if (dataTable.location) {
    yield dataTable.location;
  }

  if (dataTable.rows) {
    for (const row of dataTable.rows) {
      yield* traverseRow(row);
    }
  }
}

function* traverseRow(row: TableRow) {
  yield row;

  if (row.location) {
    yield row.location;
  }

  if (row.cells) {
    for (const cell of row.cells) {
      yield* traverseCell(cell);
    }
  }
}

function* traverseCell(cell: TableCell) {
  yield cell;

  if (cell.location) {
    yield cell.location;
  }
}

function* traverseExample(example: Examples) {
  yield example;

  if (example.location) {
    yield example.location;
  }

  if (example.tableHeader) {
    yield* traverseRow(example.tableHeader);
  }

  if (example.tableBody) {
    for (const row of example.tableBody) {
      yield* traverseRow(row);
    }
  }
}

export type Background = {
  location: Location;
  keyword: string;
  name: string;
  description: string;
  steps: readonly Step[];
  id: string;
};
export type Comment = {
  location: Location;
  text: string;
};
export type DataTable = {
  location: Location;
  rows: readonly TableRow[];
};
export type DocString = {
  location: Location;
  mediaType?: string;
  content: string;
  delimiter: string;
};
export type Examples = {
  location: Location;
  tags: readonly Tag[];
  keyword: string;
  name: string;
  description: string;
  tableHeader?: TableRow;
  tableBody: readonly TableRow[];
  id: string;
};
export type Feature = {
  location: Location;
  tags: readonly Tag[];
  language: string;
  keyword: string;
  name: string;
  description: string;
  children: readonly FeatureChild[];
};
export type FeatureChild = {
  rule?: Rule;
  background?: Background;
  scenario?: Scenario;
};
export type Rule = {
  location: Location;
  tags: readonly Tag[];
  keyword: string;
  name: string;
  description: string;
  children: readonly RuleChild[];
  id: string;
};
export type RuleChild = {
  background?: Background;
  scenario?: Scenario;
};
export type Scenario = {
  location: Location;
  tags: readonly Tag[];
  keyword: string;
  name: string;
  description: string;
  steps: readonly Step[];
  examples: readonly Examples[];
  id: string;
};
export type Step = {
  location: Location;
  keyword: string;
  keywordType?: StepKeywordType;
  text: string;
  docString?: DocString;
  dataTable?: DataTable;
  id: string;
};
export type TableCell = {
  location: Location;
  value: string;
};
export type TableRow = {
  location: Location;
  cells: readonly TableCell[];
  id: string;
};
export type Tag = {
  location: Location;
  name: string;
  id: string;
};
export type Location = {
  line: number;
  column?: number;
};
export declare enum StepKeywordType {
  UNKNOWN = "Unknown",
  CONTEXT = "Context",
  ACTION = "Action",
  OUTCOME = "Outcome",
  CONJUNCTION = "Conjunction",
}

πŸ™ Actual behavior

The implicit type signature of traverseFeatureChild() contains a return value of a generator that doesn't include FeatureChild, even though that is the first yielded element. If one comments out the if-block in said function, it suddenly appears in the type signature.

πŸ™‚ Expected behavior

For FeatureChild to be included in the type signature.

Additional information about the issue

The traverse code is part of @badeball/cypress-cucumber-preprocessor and the types are from @cucumber/messages. In v33.0.0 of @cucumber/messages, the exported types changed from classes to types, which is when this problem of mine started to appear.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions