假设我有一个包含换行符的文本字符串,我将其渲染为:
render() {
var text = "One\nTwo\nThree";
return <div>{text}</div>;
}
Run Code Online (Sandbox Code Playgroud)
在HTML中,换行符不会呈现为换行符.我应该如何在React中做到这一点?我不想转换为<br>标签和使用dangerouslySetInnerHTML.还有另外一种方法吗?
使用带有React的TypeScript,我们不再需要扩展React.Props,以便编译器知道所有的反应组件道具都可以有子代:
interface MyProps { }
class MyComponent extends React.Component<MyProps, {}> {
public render(): JSX.Element {
return <div>{this.props.children}</div>;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,无状态功能组件似乎不是这样的:
const MyStatelessComponent = (props: MyProps) => {
return (
<div>{props.children}</div>
);
};
Run Code Online (Sandbox Code Playgroud)
发出编译错误:
错误:(102,17)TS2339:"MyProps"类型中不存在属性"children".
我想这是因为编译器真的没办法知道children在props参数中会给出一个vanilla函数.
所以问题是我们应该如何在TypeScript中使用无状态功能组件中的子项?
我可以回到以前的方式MyProps extends React.Props,但Props界面被标记为已弃用,无状态组件没有或支持Props.ref我理解它.
所以我可以children手动定义道具:
interface MyProps {
children?: React.ReactNode;
}
Run Code Online (Sandbox Code Playgroud)
第一:是ReactNode正确的类型?
第二:我必须将子项写为optional(?),否则消费者会认为它children应该是component()的属性,<MyStatelessComponent children={} />如果没有提供值,则会引发错误.
好像我错过了一些东西.任何人都可以清楚地说明我的最后一个例子是否是在React中使用无子功能组件和子项的方法?
有没有办法让TypeScript枚举与JSON中的字符串兼容?
例如:
enum Type { NEW, OLD }
interface Thing { type: Type }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // false
Run Code Online (Sandbox Code Playgroud)
我想 thing.type == Type.NEW是真的.或者更具体地说,我希望我可以指定enum要定义为字符串的值,而不是数字.
我知道我可以使用,thing.type.toString() == Type[Type.NEW]但这很麻烦,似乎使枚举类型注释混乱和误导,这违背了它的目的.从技术上讲,JSON 不提供有效的枚举值,因此我不应该将属性键入枚举.
所以我现在正在做的是使用带有静态常量的字符串类型:
const Type = { NEW: "NEW", OLD: "OLD" }
interface Thing { type: string }
let thing:Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW); // true
Run Code Online (Sandbox Code Playgroud)
这让我得到了我想要的用法,但是类型注释string太宽泛且容易出错.
我有点惊讶JavaScript的超集没有基于字符串的枚举.我错过了什么吗?有没有不同的方法可以做到这一点?
更新TS 1.8
使用字符串文字类型是另一种选择(感谢@basaret),但要获得所需的类似枚举的用法(上图),它需要定义两次值:一次是字符串文字类型,一次是值(常量或命名空间):
type Type …Run Code Online (Sandbox Code Playgroud) 总之,是否可以使用一个声明某些基本属性的接口,但不限制其他属性?这是我目前的情况:
我正在使用Flux模式,它定义了一个通用调度程序:
class Dispatcher<TPayload> {
dispatch(arg:TPayload):void { }
}
Run Code Online (Sandbox Code Playgroud)
然后我创建一个具有自己的有效负载类型的调度程序,如下所示:
interface ActionPayload {
actionType: string
}
const dispatcher = new Dispatcher<ActionPayload>();
Run Code Online (Sandbox Code Playgroud)
现在我有一些动作代码应该用一些额外的数据调度有效载荷,但ActionPayload接口只允许actionType.换句话说,这段代码:
interface SomePayload extends ActionPayload {
someOtherData: any
}
class SomeActions {
doSomething():void {
dispatcher.dispatch({
actionType: "hello",
someOtherData: {}
})
}
}
Run Code Online (Sandbox Code Playgroud)
出现编译错误,因为someOtherData与ActionPayload接口不匹配.问题是许多不同的"动作"类会重复使用同一个调度程序,所以虽然它在someOtherData这里可能会anotherKindOfData在那里,依此类推.目前,我所能做的就是使用它,new Dispatcher<any>()因为会发送不同的动作.ActionPayload但是,所有操作共享一个基础,所以我希望能够限制类型new Dispatcher<extends ActionPayload>()或类似的东西.有可能吗?
TypeScript 2.1现在支持对象传播/休息,因此不再需要解决方法!
TypeScript支持JSX扩展属性,这些属性在React中通常用于将HTML属性从组件传递到呈现的HTML元素:
interface LinkProps extends React.HTMLAttributes {
textToDisplay: string;
}
class Link extends React.Component<LinkProps, {}> {
public render():JSX.Element {
return (
<a {...this.props}>{this.props.textToDisplay}</a>
);
}
}
<Link textToDisplay="Search" href="http://google.com" />
Run Code Online (Sandbox Code Playgroud)
但是,如果将任何未知道具传递给HTML元素,React会引入警告.上面的例子会产生一个React运行时警告,它textToDisplay是一个未知的支柱<a>.针对此示例的案例的建议解决方案是使用对象rest属性来提取自定义道具并将其余部分用于JSX spread属性:
const {textToDisplay, ...htmlProps} = this.props;
return (
<a {...htmlProps}>{textToDisplay}</a>
);
Run Code Online (Sandbox Code Playgroud)
但是TypeScript还不支持这种语法.我知道希望有一天我们能够在TypeScript中做到这一点.(更新:TS 2.1现在支持对象传播/休息!为什么你还在读这个?)同时有什么解决方法?我正在寻找一种不会影响类型安全性并且发现它非常困难的解决方案.例如,我可以这样做:
const customProps = ["textDoDisplay", "otherCustomProp", "etc"];
const htmlProps:HTMLAttributes = …Run Code Online (Sandbox Code Playgroud) 我在弄清楚如何正确键入Redux容器时遇到了一些麻烦.
考虑一个简单的表示组件,可能如下所示:
interface MyProps {
name: string;
selected: boolean;
onSelect: (name: string) => void;
}
class MyComponent extends React.Component<MyProps, {}> { }
Run Code Online (Sandbox Code Playgroud)
从这个组件的角度来看,所有道具都是必需的.
现在我想编写一个容器,将所有这些道具拉出状态:
function mapStateToProps(state: MyState) {
return {
name: state.my.name,
selected: state.my.selected
};
}
function mapDispatchToProps(dispatch: IDispatch) {
return {
onSelect(name: string) {
dispatch(mySelectAction(name));
}
};
}
const MyContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
Run Code Online (Sandbox Code Playgroud)
这是有效的,但是有一个很大的打字问题:映射函数(mapStateToProps和mapDispatchToProps)没有保护它们提供正确的数据来实现MyProps.这容易出错,拼写错误和重构不佳.
我可以使映射函数返回类型MyProps:
function mapStateToProps(state: MyState): MyProps { }
function mapDispatchToProps(dispatch: IDispatch): MyProps { } …Run Code Online (Sandbox Code Playgroud) 在TypeScript + React项目中,我使用的是react-dnd及其DefinitelyTyped类型:
interface ExampleScreenProps { a, b, c }
interface ExampleScreenState { x, y, z }
class ExampleScreen extends React.Component<ExampleScreenProps, ExampleScreenState> { }
export default DragDropContext(HTML5Backend)(ExampleScreen);
Run Code Online (Sandbox Code Playgroud)
这将在另一个组件中呈现:
import ExampleScreen from "./ExampleScreen";
<ExampleScreen a="a" b="b" c="c" />
Run Code Online (Sandbox Code Playgroud)
这适用于TS 1.8,没有任何错误.当我升级到TS 2.0时,我得到以下编译错误:
错误:(90,10)TS2600:JSX元素属性类型'(ExampleScreenProps&{children?:ReactNode;})| (ExampleScreenProps&{children ...'可能不是联合类型.
这是以下类型的定义DragDropContext:
export function DragDropContext<P>(
backend: Backend
): <P>(componentClass: React.ComponentClass<P> | React.StatelessComponent<P>) => ContextComponentClass<P>;
Run Code Online (Sandbox Code Playgroud)
我不能把它放在一起.抱怨的错误是什么?它似乎不喜欢联合ComponentClass<P> | StatelessComponent<P>,但那些不是元素属性,元素属性很简单<P>.我尝试明确传递<P>:
export default DragDropContext<ExampleProps>(HTML5Backend)(ExampleScreen);
Run Code Online (Sandbox Code Playgroud)
但同样的错误仍然存在.我可以通过声明输出来解决它:
export default DragDropContext(HTML5Backend)(ExampleScreen) as …Run Code Online (Sandbox Code Playgroud) 我正在使用一个async函数来调用现有的基于promise的API,该API拒绝带有类型错误的promise.
你可以像这样模仿这种行为:
interface ApiError {
code: number;
error: string;
}
function api(): Promise<any> {
return new Promise((resolve, reject) => {
reject({ code: 123, error: "Error!" });
});
}
Run Code Online (Sandbox Code Playgroud)
现在有了promises,我可以将错误类型注释为ApiError:
api().catch((error: ApiError) => console.log(error.code, error.message))
Run Code Online (Sandbox Code Playgroud)
但是在使用时,async如果我尝试在以下位置注释错误类型try ... catch():
async function test() {
try {
return await api();
} catch (error: ApiError) {
console.log("error", error);
}
}
Run Code Online (Sandbox Code Playgroud)
它编译错误:
Catch子句变量不能有类型注释.
那么,我怎么知道我期待的是什么样的错误?我需要在catch()块中写一个断言吗?这是异步的错误/不完整功能吗?
我现在使用npm install @types/angularTypeScript 2.0,到目前为止的经验比以前更顺畅typings.
我有一个使用ES6模块和Webpack的Angular 1.5项目,它与这个初学者项目非常相似.
我正在尝试为Angular 1.5 安装打字.我tsd过去曾经用过,但这是我第一次尝试使用新的typings经理.
当我尝试时,typings install angular我得到:
"Unable to find "angular" ("npm") in the registry."
Run Code Online (Sandbox Code Playgroud)
当我跑步时,typings search angular我看到了一个结果NAME: angular, SOURCE: dt.
当我尝试时,typings install angular dt~angular我得到:
"Attempted to compile "angular" as an external module, but it looks like a global module."
Run Code Online (Sandbox Code Playgroud)
但是,当我查看DefinitelyTyped/angular.d.ts时,我看到虽然它确实声明了一个全局angular变量,但它也声明了一个模块"angular",因为许多DefinitelyTyped定义都支持UMD.
我如何才能使用打字机?或者我应该坚持下去tsd?
有没有办法为JSX中呈现的组件指定类型参数?
例如,考虑以下组件:
interface SelectorProps<T> {
selection: T;
options: T[];
}
class Selector<T> extends React.Component<SelectorProps<T>, {}> {
// ...
}
Run Code Online (Sandbox Code Playgroud)
如果我尝试在JSX中呈现此组件:
<Selector selection="a" options={["a", "b", "c"]} />
Run Code Online (Sandbox Code Playgroud)
我收到这些错误:
TS2322:类型'string'不能分配给'T'类型.
TS2322:类型'string []'不能分配给'T []'.类型'string'不能分配给'T'类型.
我希望T被推断为string,否则一些方法来指定T=string在<Selector>.有解决方案吗?
我发现的唯一解决方法是扩展组件以消除所有类型参数:
class StringSelector extends Selector<string> { }
Run Code Online (Sandbox Code Playgroud) typescript ×9
reactjs ×6
angularjs ×1
enums ×1
generics ×1
json ×1
react-dnd ×1
react-jsx ×1
react-redux ×1
redux ×1