Skip to content

Contextual type of a property type not inferred with key remappingΒ #48855

@Andarist

Description

@Andarist

Bug Report

πŸ”Ž Search Terms

contextual, template literal, key remapping, object property

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

interface MachineConfig<TEvent extends { type: string }> {
  schema?: {
    events?: TEvent;
  };
  on?: {
    [K in TEvent["type"] as `on${K}`]?: (
      ev: TEvent extends { type: K } ? TEvent : never
    ) => void;
  };
}

declare function createMachine<TEvent extends { type: string }>(
  config: MachineConfig<TEvent>
): void;

export default createMachine({
  schema: {
    events: {} as { type: "FOO" },
  },
  on: {
    onFOO: (ev) => {
      ev.type; // should be `FOO`, but `ev` is an implicit `any`
    },
  },
});

πŸ™ Actual behavior

Implicit any is reported

πŸ™‚ Expected behavior

ev should get inferred as { type: 'FOO' }


getTypeOfPropertyOfContextualType explicitly~ ignores this case:

if (isGenericMappedType(t) && !t.declaration.nameType) {
    const constraint = getConstraintTypeFromMappedType(t);
    const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
    const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
    if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
        return substituteIndexedMappedType(t, propertyNameType);
    }
}

Note that nameTypecomes from an argument provided by this call within getContextualTypeForObjectLiteralElement but it's undefined:

getTypeOfPropertyOfContextualType(type, symbol.escapedName, getSymbolLinks(symbol).nameType);

I guess the fix here would be to not ignore this potential substitution based on !t.declaration.nameType and construct the possible K constraint based on the t.declaration.nameType and name. I don't know how to do this in a sufficiently generic manner though.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions