إذا كنت تعرف كيفية إصلاح المشكلة ، فقم بتقديم طلب سحب بدلاً من ذلك.
@types/react
وواجهت مشاكل.Definitions by:
في index.d.ts
) حتى يتمكنوا من ذلك رد.إذا لم تذكر المؤلفين ، فسيتم تجاهل المشكلة.
لا يمكنني الاتصال بـ setState
مع إنشاء كائن من اسم خاصية محسوبة باستخدام type-safety:
type State = {
username: string,
password: string
};
type StateKeys = keyof State;
class A extends React.Component<{}, State> {
dynSetState(key: StateKeys, value: string) {
this.setState({
[key]: value // Error here. Pretty sure key is in StateKeys
});
}
}
أنا على علم بـ # 18365 ، والحل البديل في https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment -351868649. ومع ذلك ، عند استخدام الحل البديل ، لا يخطئ Typescript في حدوث ما يلي:
dynLooselySetState(key: string, value: string) {
this.setState(prevState => ({
...prevState,
[key]: value // No error here, but can't ensure that key is in StateKeys
}));
}
هذا تقييد للمترجم نفسه ، الأنواع المستنبطة عبر مفاتيح الخصائص المحسوبة لا تدعم أنواع الاتحاد ، فهي تدعم فقط string
، number
، symbol
أو حرف واحد من هؤلاء 3 ، إذا اكتشف أنه اتحاد لأي من هؤلاء ، فسيتم فقط إجباره على النوع العام string
. سيكون الحل هنا هو إجبار الكائن:
dynSetState(key: StateKeys, value: string) {
this.setState({
[key]: value
} as Pick<State, keyof State>)
}
سيظل هذا يعطي خطأ مناسبًا إذا لم تكن القيمة في مجموعة أنواع قيمة الخاصية المحتملة ، ولكنه لن يعطيك خطأ إذا لم تكن المفاتيح ضمن مجموعة مفاتيح الخصائص المحتملة.
بالضبط ما ferdaber على الرغم من أن
حسن:
class C extends Component<{}, State> {
updateState(key: StateKeys, value: string) {
this.setState((prevState) => ({
...prevState,
[key]: value,
}));
}
}
أفضل:
const updateState = <T extends string>(key: keyof State, value: T) => (
prevState: State
): State => ({
...prevState,
[key]: value
})
class C extends Component<{}, State> {
doSomething(){
this.setState(updateState('password','123124'))
}
}
لم أجد مشكلة ذات صلة بهذا القيد في الريبو المطبوع على الورق .. هل هناك فرصة لتعرف ما إذا كان هذا قد تمت مناقشته (وأين) في الريبو المطبوع عليه؟ أتساءل بشكل أساسي عما إذا كانت هناك بعض الخطط لمعالجة هذا في الإصدارات المطبوعة في المستقبل.
شكرا!
ها هي المناقشة وملاحظات التصميم من فريق TS ومحاولة إصلاحها (والتي أعتقد أنه تم التراجع عنها لإصدار مستقبلي):
https://github.com/Microsoft/TypeScript/issues/13948
https://github.com/Microsoft/TypeScript/issues/18155
https://github.com/Microsoft/TypeScript/pull/21070
في الواقع ، ما أحاول تحقيقه هو القيام بشيء مثل هذا: https://reactjs.org/docs/forms.html#handling -multiple-inputs
مما يسهل التعامل مع نموذج ذي مدخلات متعددة. قد لا يزال يتعين علي التأكد من أن سمة "الاسم" هي ما نتوقعه ، ولكن بعد ذلك يجب أن تعمل سلامة النوع.
اضطررت إلى إضافة as unknown
إلى حل ferdaber :
this.setState({
[key]: value
} as unknown as Pick<State, keyof State>)
هذا حذر إذا كان key
قيمة منطقية ، لكن ليس إذا كان رقمًا!
لذلك اخترت هذا الحل الأقصر:
this.setState<never>({
[key]: value
})
هذا يحذر إذا كان key
هو
لماذا يعمل https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635#issuecomment -400260278؟ أعني المفتاح لا يزال نوع النقابة؟
ربما هذا سوف تساعدك
type IAction = {
[P in keyof IAppSettings]?: IAppSettings[P];
};
function reducer(state: IAppSettings, action: IAction) {
return {
...state,
...action,
};
}
هل هناك تقدم في هذه القضية؟
كنت قادرا على الحصول على هذا العمل
handleTextChange(name: keyof State, value: any) {
this.setState({
...this.state,
[name]: value
});
}
بالنسبة للآخرين الذين ينظرون إلى هذا ويحاولون تطبيقه على أنواع حالاتهم الخاصة ، لاحظ أن نوع value
في المنشور الأصلي والردود هو string
فقط لأن جميع أنواع العقارات في State
هي string
. قد يكون من الأفضل تجنب استخدام any
أو صب إضافي عند تضمين أنواع أخرى ، وبدلاً من ذلك تقييد الأنواع مثل نوع value
يتوافق مع نوعه المطابق لنوع المفتاح.
interface State {
name: string;
age: number;
}
type StateKeys = keyof State;
function dynSetState<K extends StateKeys>(key: K, value: State[K]) {
this.setState({ [key]: value }); // fails; if only this worked...
this.setState({ [key]: value } as Pick<State, K>); // clean cast works
this.setState((s, _) => ({ ...s, [key]: value })); // avoids cast, but changes js
}
dynSetState("name", "a"); // works as expected
dynSetState("name", 1); // fails as expected
dynSetState("age", "a"); // fails as expected
dynSetState("age", 1); // works as expected
لماذا يعمل # 26635 (تعليق) ؟ أعني المفتاح لا يزال نوع النقابة؟
إنه يعمل لأن نوع { ...prevState }
سيتطابق بشكل كافٍ مع State
، بشكل أساسي لأن لدينا على الأقل جميع خصائص الدولة. قد يساعد في فهم سبب عدم نجاحه بدونه. جذر المشكلة هو أن نوع الكائن الذي تم إنشاؤه: { [key: K]: State[K] }
ليس محددًا بدرجة كافية ؛ إنه { [x: string]: State[K] }
الذي لا يمكنه تحويل المفتاح string
إلى keyof State
.
مجرد إضافة إلى arinwt كمثال آخر.
TL ؛ DR: الحل النهائي في الأسفل
الحل الموسع مع وجود أخطاء في وحدة التحكم:
type RegisterTypes = {
email: string;
password: string;
}
// ...
const [state, setState] = useState<RegisterTypes>({
email: "",
password: "",
});
// ...
const onChangeInput = (key: keyof RegisterTypes) => (event: React.ChangeEvent<HTMLInputElement>) => {
setState({
[key]: event.target.value
} as Pick<RegisterTypes, typeof key>);
};
// ...
<input type="email" onChange={onChangeInput('email')} value={state.email} />
على الرغم من أن هذا يعطيني الخطأ التالي في وحدة التحكم:
Warning: A component is changing a controlled input of type password to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
الحل البديل (الغش) مع وجود أخطاء في وحدة التحكم:
يعطي التحذير أيضا.
type RegisterTypes = {
[key: string]: string;
}
// ...
const onChangeInput = (key: string) => (event: React.ChangeEvent<HTMLInputElement>) => {
setState({
[key]: event.target.value
});
};
الحل النهائي لا أخطاء:
type RegisterTypes = {
email: string;
password: string;
}
// ...
const onChangeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const newState = { ...state };
newState[event.target.name as keyof RegisterTypes] = event.target.value;
setState(newState);
};
// ...
<input name="email" type="email" onChange={onChangeInput} value={state.email} />
التعليق الأكثر فائدة
هذا تقييد للمترجم نفسه ، الأنواع المستنبطة عبر مفاتيح الخصائص المحسوبة لا تدعم أنواع الاتحاد ، فهي تدعم فقط
string
،number
،symbol
أو حرف واحد من هؤلاء 3 ، إذا اكتشف أنه اتحاد لأي من هؤلاء ، فسيتم فقط إجباره على النوع العامstring
. سيكون الحل هنا هو إجبار الكائن:سيظل هذا يعطي خطأ مناسبًا إذا لم تكن القيمة في مجموعة أنواع قيمة الخاصية المحتملة ، ولكنه لن يعطيك خطأ إذا لم تكن المفاتيح ضمن مجموعة مفاتيح الخصائص المحتملة.