#match function parameter to object value

1 messages · Page 1 of 1 (latest)

sharp mauve
#
export type PainterData = RasterData | SensorData | FillData | LineData | PointData | HeatmapData | GlyphData

export interface Workflow {
  fill?: FillProgram
  glyphFilter?: GlyphFilterProgram
  glyph?: GlyphProgram
  heatmap?: HeatmapProgram
  line?: LineProgram
  point?: PointProgram
  raster?: RasterProgram
  sensor?: SensorProgram
  shade?: ShadeProgram
  background?: WallpaperProgram | SkyboxProgram
}

const workflows: Workflow = { ... }

function buildFeatureData (tile: Tile, data: PainterData): void {
    const workflow = workflows[data.type]
    if (workflow === undefined) throw new Error(`Workflow ${data.type} not found`)
    workflow.buildSource(data as any, tile)
  }

I would like for data to work properly. FillData should always map to FillProgram and so on. But it natrually resolves to never and I can't think of a way to fix this -_-

Argument of type 'PainterData' is not assignable to parameter of type 'never'.
  The intersection 'FillData & GlyphData & HeatmapData & LineData & PointData & RasterData & SensorData' was reduced to 'never' because property 'type' has conflicting types in some constituents.
    Type 'RasterData' is not assignable to type 'never'.ts(2345)
(parameter) data: PainterData
versed crane
#

i think this is the correspondence problem

#

!:correspondence-problem

sharp sinewBOT
#
retsam19#0
`!retsam19:correspondence-problem`:

There's a particular pattern that is safe but hard for the Typescript compiler to handle, which I call the "correspondence problem":

const functionsWithArguments = [
  { func: (arg: string) => {}, arg: "foo" },
  { func: (arg: number) => {}, arg: 0 },
];

for (const { func, arg } of functionsWithArguments) {
  func(arg);
//     ^^^
// Argument of type 'string | number' is not assignable to parameter of type 'never'.
//   Type 'string' is not assignable to type 'never'.
}

The problem is that func is typed as (x: string) => void | (x: number) => void and arg is string | number, but the compiler can't prove that they "correspond": that, for example, arg is only a string when func accepts strings.

As far as the type are concerned, arg could be number, and func could be (arg: string) => void, and that would be a type-error. It's easy for us to see that that won't happen, but that requires understanding the program at a higher-level than the level the compiler operates.

Depending on the specifics there's sometimes clever fixes, but usually I recommend using a type assertion and ignoring the issue:

func(arg as never);