Тип "число []" пропускает следующие свойства из типа "[число, число, число, число]": 0, 1, 2, 3

70
6

type padding = [number, number, number, number]

interface IPaddingProps {
defaultValue?: padding
className?: string
disabled?: boolean
min?: number
max?: number
onChange?: (value: number | string) => void
}
interface IFieldSate {
value: padding
}
export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {

readonly state = {
value: [0, 0, 0, 0]
}
constructor(props: IPaddingProps) {
super(props)
if (props.defaultValue) {
this.state.value = [...props.defaultValue]
}
}

}

Я получаю ошибку в state говоря:

Тип "число []" пропускает следующие свойства из типа "[число, число, число, число]": 0, 1, 2, 3?

спросил(а) 2019-02-23T08:41:00+03:00 1 год, 7 месяцев назад
1
Решение
57

Ваша проблема в том, что state выводится как массив, а не как кортеж. Есть несколько способов обойти это, как подробно описано в этом ответе. Я просто представлю один из них здесь.

Предполагая, что вы используете TypeScript 3.0 или выше, вы можете определить следующую вспомогательную функцию tuple() которая принимает любое количество аргументов и возвращает кортеж из этих аргументов:

type Narrowable = string | number | boolean | undefined | null | void | {};
const tuple = <T extends Narrowable[]>(...t: T)=> t;

Затем вы можете использовать его внутри определения класса FieldPadding:

export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {
readonly state = {
value: tuple(0, 0, 0, 0)
}
}

и это дает value типу [0, 0, 0, 0], типу кортежа с четырьмя элементами числового литерального типа 0.

ОБНОВИТЬ:

Итак, вы хотите, чтобы state было readonly только для readonly но вы хотите изменить значения state.value с 0 на другие числа? 🤷

В этом случае вы хотите, чтобы value было тип [number, number, number, number], которое шире, чем [0, 0, 0, 0] но уже, чем number[]. Вы можете сами это комментировать, что я бы порекомендовал, если вы хотите такой строгий контроль над типом:

export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {
readonly state = {
value: [number, number, number, number] = [0, 0, 0, 0]
}
}

Вы могли бы также сделать

export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {
readonly state = {
value: tuple(0 as number, 0 as number, 0 as number, 0 as number)
}
}

или же

const z: number = 0;
export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {
readonly state = {
value: tuple(z, z, z, z)
}
}

или даже сделать менее сужающую функцию tuple()

const wideTuple = <T extends any[]>(...t: T) => t;
export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {
readonly state = {
value: wideTuple(0, 0, 0, 0)
}
}

Любой из них должен работать для вас. Краткий ответ на заданный вопрос заключается в том, что вам нужен тип кортежа, а не массив. Как именно вы получаете это зависит от вас.

Надеюсь, это поможет; удачи!

ответил(а) 2019-02-23T17:20:00+03:00 1 год, 7 месяцев назад
57

Вместо того, чтобы записывать тип значения в виде массива с 4 элементами типа номер, вы должны написать type padding = number[] или type padding = Array<number>


type padding = number[]

interface IPaddingProps {
defaultValue?: padding
className?: string
disabled?: boolean
min?: number
max?: number
onChange?: (value: number | string) => void
}
interface IFieldSate {
value: padding
}
export default class FieldPadding extends React.Component<IPaddingProps, IFieldSate> {

readonly state = {
value: [0, 0, 0, 0]
}
}

ответил(а) 2019-02-23T08:44:00+03:00 1 год, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема