当前位置: 首页 > 知识库问答 >
问题:

Typescript允许使用错误的类型设置上下文属性

吕宣
2023-03-14

我对react、react hooks和js/ts非常陌生。

目前,我正在编码一个简单的按钮,它通过useContext获取一个状态,并通过useReucer和调度函数更新该状态。

我试图将我所有的代码分离到特定的文件中。来自减速器的调度函数在提供程序中作为值传递。

当我在使用者组件中调用传递的函数时,我可以给它一个任何类型的值(在我的示例中是数字)给调度器。我在上下文、reducer等中设置了所有类型。VSCode告诉我它期望的类型-似乎都是正确的。它仍然允许任何类型的人通过。为什么呢?我试图安慰他。在传递值的所有点上进行日志记录,它似乎用类型编号覆盖类型,忽略我指定的类型。

//app-state.tsx:
export type AppState = {
  readonly FoldoutPosition: number | null,
  readonly FoldoutType: FoldoutType | null
}

enum FoldoutType {
  Projects,
  Connection
}
//app-context.tsx
import { createContext, Dispatch } from 'react'
import { AppState} from '../states/app-state'

type ContextState =
  { AppState: AppState } &
  { changeFoldoutPosition: Dispatch<AppState["FoldoutPosition"]> } &
  { changeFoldoutType: Dispatch<AppState["FoldoutType"]> }


  export default createContext<ContextState>({
    AppState: {
      FoldoutType: null,
      FoldoutPosition: 0
    },
    changeFoldoutPosition: () => { },
    changeFoldoutType: () => { }
  });
//reducer.tsx
import { AppState } from '../states/app-state'


type Action =
    | { readonly type: 'CHANGE_FOLDOUTPOSITION', readonly payload: AppState["FoldoutPosition"] }
    | { readonly type: 'CHANGE_FOLDOUTTYPE', readonly payload: AppState["FoldoutType"] };


export const reducer = (state: AppState, action: Action): AppState => {

    switch (action.type) {
        case 'CHANGE_FOLDOUTPOSITION':
            return { ...state, FoldoutPosition: action.payload };
        case 'CHANGE_FOLDOUTTYPE':
                return { ...state, FoldoutType: action.payload };
        default:
            return state
    }

}
//wrapper.tsx
import React, { useReducer } from 'react'
import { reducer } from '../reducers/reducer'

import AppContext from './app-context'
import {AppState} from '../states/app-state'

const AppWrapper = (props: any) => {

  const initalState = {
    FoldoutType: null,
    FoldoutPosition: 15
  }

  const [state, dispatch] = useReducer(reducer, initalState);

  const changeFoldoutPosition = (FoldoutPosition: AppState["FoldoutPosition"]) => {
    dispatch({type: 'CHANGE_FOLDOUTPOSITION', payload: FoldoutPosition});
  }

  const changeFoldoutType = (FoldoutType: AppState["FoldoutType"]) => {
    dispatch({type: 'CHANGE_FOLDOUTTYPE', payload: FoldoutType});
  }

  return (
    <AppContext.Provider  
      value={{
        AppState: state,
        changeFoldoutPosition: changeFoldoutPosition,
        changeFoldoutType: changeFoldoutType
      }}
    >
      {props.children}
    </AppContext.Provider>
  );
}

export default AppWrapper;
/// component:
import React, { useContext } from 'react'
import AppContext from '../contexts/app-context'

const TestComponent = (props: any) => {

    const context = useContext(AppContext);

    return (
        //{context.AppState.Foldout}
        <div>
            <button onClick={() => context.changeFoldoutPosition(10)}>
                1 - {context.AppState.FoldoutPosition} - {context.AppState.FoldoutType}
                </button>
            // The following button onClick should not work
            // Type should be restricted to <FoldoutType | null>
            <button onClick={() => context.changeFoldoutType(23)}>
                2 - {context.AppState.FoldoutPosition} - {context.AppState.FoldoutType}
                </button>
        </div>
    );
}

export default TestComponent 

共有1个答案

阎京
2023-03-14

这与React无关,这是一个纯类型脚本问题。TypeScript中的枚举具有自动递增功能,如果未指定,默认情况下会使用数字初始化键。

从文档中:

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

在这里,Up的值为0,Down的值为1,等等。

这就是changeFoldoutType允许将整数作为参数传递的原因:TypeScript枚举允许它。

对于您的示例,您的TypeScript代码...

type AppState = {
  readonly FoldoutPosition: number | null,
  readonly FoldoutType: FoldoutType | null
}

enum FoldoutType {
  Projects,
  Connection
}

const testFn = (foldoutType: AppState["FoldoutType"]) => {
    console.log(foldoutType)
}

testFn(1)

console.log(FoldoutType)
// { 
//   "0": "Projects",
//   "1": "Connection",
//   "Projects": 0,
//   "Connection": 1
// }

...编译成类似的JavaScript,在那里你可以清楚地看到访问Enum键的数字:

var FoldoutType;

(function (FoldoutType) {
    FoldoutType[FoldoutType["Projects"] = 0] = "Projects";
    FoldoutType[FoldoutType["Connection"] = 1] = "Connection";
})(FoldoutType || (FoldoutType = {}));

const testFn = (foldoutType) => {
    console.log(foldoutType);
};

testFn(1);

console.log(FoldoutType);
 类似资料:
  • LineSeries['areaStyle']的类型是AreaStyle | undefined 报错:类型“AreaStyle | undefined”上不存在属性“color”。 如何通过 LineSeries使用color属性的类型呢?

  • 问题内容: 我正在学习使用课程,而我的作业的一部分是参加汽车课。我在第6行遇到错误,尝试在该行中打印方法的结果。我认为这意味着我正在尝试打印不存在的内容,并且我怀疑这是里程方法。我尝试将其更改为返回英里,但这也没有用。有任何想法吗? 问题答案: 该错误消息告诉您确切的问题是什么-您正试图从不返回结果的方法中提取结果。 而是让方法 返回 字符串,而不是打印出字符串。 我本人将使它成为一种吸气剂方法,

  • 我试图设置请求的内容类型标题,但是okhttp会自动将内容类型添加到标题列表的末尾,并将其设置为application/json;charset=UTF-8,尽管我只是将其设置为application/json。 还有其他人经历过吗?如果是的话,我可以提出请求。 我发现okhttp没有通过fiddler正确发送此标头。

  • 问题内容: 我正在迁移带有TypeScript的React项目以使用钩子功能(React v16.7.0-alpha),但是我不知道如何设置已分解元素的类型。 这是一个例子: 我想强制变量为type 。我唯一成功的试用是分两个阶段进行的:键入,然后初始化: 但是我敢肯定有更好的方法。另外,应将其初始化为以a 作为输入但不返回任何内容的函数。 另外,值得注意的是,不进行任何初始化就可以正常使用,但是

  • 我已将TS添加到我的React/Redux应用程序中。 我在我的应用程序中使用对象,如下所示: TS抛出一个错误: 类型脚本错误:类型“窗口”上不存在属性“FB”。TS2339 我想修正这个错误。 我在这里找到了答案https://stackoverflow.com/a/56402425/1114926 为什么第一个版本不起作用,而第二个版本起作用,尽管我根本没有指定FB属性?

  • 不过,当我尝试使用firebase数据库时,我做了一个const来获取firebase数据库中的现有房间。get()在线:const roomRef=await database。ref()。get(); 它报告以下错误:D:/react/app/letmeask/src/pages/Home中的TypeScript错误。tsx(35,65):类型“Reference”上不存在属性“get”。TS