Skip to content

Can't discriminate node.parent node's type in Typescript #2048

@Goodwine

Description

@Goodwine

The node.parent value returns a ContainerWithChildren type. This interface extends Node directly, so it is not possible to determine at compile-type which type of node is the parent node just by looking at type. It is only possible to do at runtime, and this makes the interface not very useful for Typescript.

Example TS code [stackblitz]:

import postcss from 'postcss';

const { root } = postcss([]).process('@a{.b{}}').sync();
const [atRule] = root.nodes;
if (atRule.type !== 'atrule') throw new Error('not at-rule');
const [rule] = atRule.nodes ?? [];
if (rule.type !== 'rule') throw new Error('not rule');
const { parent } = rule;

switch (parent?.type) {
  case 'rule':
  case 'comment':
  case 'atrule':
  case 'decl':
  case 'root':
  case undefined:
    console.log('yay');
  default:
    // This fails because `parent` is of type `ContainerWithChildren` which is
    // an interface that extends `Node` rather than being a sumtype.
    const impossible: never = parent;
}

Arguably, the ContainerWithChildren interface should not extend Container. Instead it should be declared something like:

type ContainerWithChildren<T> = (Root | AtRule | Rule) & Container<T>;

(I haven't verified this type, but it should be something along these lines)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions