#typescript
#typescript
Вопрос:
Сначала у меня есть определение типа, отображающее все свойства в число с помощью keyof
type Numeric<T> = {
[K in keyof T]: number
}
Ниже приведен класс, который я буду использовать.
class Entity {
aNumber: number;
}
Ниже приведена функция, которая принимает аргумент универсального типа и локальную переменную с типом Numberic<T>
. Но когда я назначил { aNumber: 1 }
, это выдало ошибку компиляции.
const fn = <T extends Entity>() => {
const n: Numeric<T> = {
// ^
// Type '{ aNumber: number; }' is not
// assignable to type 'Numeric<T>'
aNumber: 1
};
};
Я не знаю, почему { aNumber: number; }
не может быть назначен Numeric<T>
, поскольку аргумент типа T
должен быть расширен с Entity
и он должен содержать ключ с именем aNumber
. Это означает, что aNumber
должен быть ключ типа T и должен иметь возможность присваиваться Numeric<T>
.
Ответ №1:
Сообщение об ошибке вводит в заблуждение. Однако есть ошибка, и это то, что ловит TypeScript. Действительно, нет ничего плохого в Entity
:
type Numeric<T> = {
[K in keyof T]: number
}
interface Entity {
aNumber: number
}
// No error
const n: Numeric<Entity> = {
aNumber: 1
};
Однако, когда вы говорите T extends Entity
, он открывает его для значений, отличных от числа, например
type Numeric<T> = {
[K in keyof T]: number
}
interface Entity {
aNumber: number
}
// No error
const n: Numeric<Entity> = {
aNumber: 1
};
interface X extends Entity {
notANumber: string
}
// Error. Thank you TypeScript
const o: Numeric<X> = {
aNumber: 1
};
Отсюда и ошибка при использовании T extends Entity
в Numeric
.
Комментарии:
1. Нет, я не думаю, что ваше объяснение правильное. Я вижу ошибку в части TS, но не в вашем случае. Проверьте мой ответ.
Ответ №2:
Ограничение, налагаемое <T extends Entity>
, следует рассматривать как минимальное требование, которому T
должно соответствовать. Это означает, что « T
должно содержать по крайней мере aNumber: number
пару».
Давайте посмотрим const n: T
. Это означает, что «n должно содержать, по крайней мере, любые пары ключ-значение, которые находятся в T
«.
Теперь мы знаем, T
имеет aNumber: number
пару, но помните, что это всего лишь минимальное требование. T
также может быть { aNumber: number; aString: string }
. Вот почему это также приведет к ошибке.
// if you understand this:
const n: { aNumber: number; aString: string } = { aNumber: 42 } // error, of course
// you see why this is an error:
const n: T = { aNumber: 42 } // also error
Вы никогда не сможете сказать, что именно T
. keyof T
все в порядке, потому что мы точно знаем хотя бы об одном из T
ключей.
const k: keyof T = "aNumber"
Чтобы доказать мою точку зрения, давайте рассмотрим нестандартный случай. Возьмем, к примеру, код @basarat, здесь X
нет genreic.
type Numeric<T> = {
[K in keyof T]: number
}
type OptionalNumeric<T> = {
[K in keyof T]?: number
}
interface Entity {
aNumber: number
}
interface X extends Entity {
notANumber: string
}
// Error, because `notANumber` is missing
const o: Numeric<X> = { aNumber: 1 };
// Correct
const o1: Numeric<X> = { aNumber: 1, notANumber: 2 };
// Also correct, because all keys are optional.
const o2: OptionalNumeric<X> = { aNumber: 1 };
Примечание сбоку. Выше следует объяснить ваш случай. Тем не менее, я считаю, что в TS есть ошибка.
Я думаю, что если вы используете OptionalNumeric
в своем исходном случае, то то, что вы хотите, должно сработать. Но, оказывается, это не так. Должен быть дефект, когда задействованы параметры универсального типа.
Комментарии:
1. ошибка все еще существует, хотя я использовал
type Numeric<T> = { [K in keyof T]?: number }
. Но если я передаю аргумент типа вNumeric<T>
, он работает хорошо, напримерconst n: Numeric<Entity>
. Но я использую общий аргумент, так как то, что я сделал в примереconst fn = <T extends Entity>() => { const n: Numeric<T> = { aNumber: 1 }; };
, не удалось.2. @ShaunXu Я говорю следующее: а) то, что вы пытаетесь сделать, неправильно; б) необязательный ключ должен работать, но это не так, и его следует считать ошибкой. У меня есть только объяснение, а не решение.
3. Обходной путь здесь (при условии, что мы используем
OptionalNumeric
) заключается в присвоенииn
типуOptionalNumeric<T amp; Entity>
вместоOptionalNumeric<T>
. Однако я не знаю, известна ли проблема сOptionalNumeric<T>
.4. Я думал, что это связано с Microsoft / TypeScript # 13442 , но я думаю, что это не так.