Home > OS >  TypeScript is not throwing errors when invalid value passed to the Props
TypeScript is not throwing errors when invalid value passed to the Props

Time:12-02

const enum ColumnValues {
  one = 1,
  two = 2,
  three = 3,
}

interface Props {
  style?: StyleProp<ViewStyle>;
  title?: string;
  titleContainerStyle?: StyleProp<ViewStyle>;
  titleStyle?: StyleProp<TextStyle>;
  textInputStyle?: StyleProp<TextStyle>;
  column?: ColumnValues.one | ColumnValues.two | ColumnValues.three;
}

const DynPut: FC<Props> = Props => {
...
return(
...
)

I have imported this DynPut into another component and passed the value 10 to the Column Prop but typescript is not throwing any errors. How to make typescript throw an error when any values greater than 3 is passed to the Column Prop

  <DynPut
    title="Add Items"
    style={{backgroundColor: 'yellow'}}
    titleStyle={{backgroundColor: 'green'}}
    titleContainerStyle={{backgroundColor: 'green'}}
    textInputStyle={{borderWidth: 5}}
    column={10}
  />

CodePudding user response:

This is very similar issue to this, however previous answer should be slightly modified to fit this problem. If you think it is a duplicate, feel free to flag it.

The main problem here is that number type in typescript is assignable to numeric enum even if it does not fit the enum values/requirements. Please see this answer to get more context.

In order to validate provided number, we need to stringify all enum numbers and provided column number. Then it is safe to validate them.

Consider this example:

enum ColumnValues {
    one = 1,
    two = 2,
    three = 3,
}

// Stringifies each enum numeric value. 
// Example: 3 -> "3"
type Enumerate<Enum> = Enum extends number | string ? keyof {
    [Prop in `${Enum}`]: Prop
} : never

// Obtain stringified enum values
type Result = Enumerate<ColumnValues> // "0" | "1"

// Obtain a union of object values
type Values<T> = T[keyof T]

// Check whether provided initial value extends stringifiedn enum value
// if yes - allow this value and return initial
// id no - return never, so TS with throe an error
type IsKeyValid<InitialValue extends number, Enum> =
    `${InitialValue}` extends Enumerate<Enum> ? InitialValue : never

type Props<Count extends number> = {
    column: IsKeyValid<Count, ColumnValues>
}
const DynPut = <Count extends number>(props: Props<Count>) => { }

DynPut({ column: 1 }) // ok
DynPut({ column: 5 }) // error

Playground

Please also see my article

  • Related