-
Notifications
You must be signed in to change notification settings - Fork 6
feat(*): add params information to func proptypes where possible #79
Merged
Merged
Changes from 7 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
c9d0a19
feat(*): add params information to func proptypes where possible
Heymdall 6136e90
feat(typings): create correct typings from jsdoc
Heymdall da0fe47
fix(typings): do not override existing d.ts
Heymdall e939da8
feat(typings): accept all HTML and React types as valid ts types
Heymdall eb2a629
feat(*): add tests, move props jsdoc parser to react-docgen handler
Heymdall eaa70ec
fix(typings): remove unused params
Heymdall 8fcc5a8
chore(travis): add test command
Heymdall 17c6f8b
feat(typings): use DeepReadonly generic
Heymdall File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ before_script: | |
|
||
script: | ||
- npm run lint | ||
- npm test | ||
|
||
after_script: | ||
- greenkeeper-lockfile-upload | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
const getMemberValuePath = require('react-docgen/dist/utils/getMemberValuePath').default; | ||
const resolveToValue = require('react-docgen/dist/utils/resolveToValue').default; | ||
const getPropertyName = require('react-docgen/dist/utils/getPropertyName').default; | ||
const parseJsDoc = require('react-docgen/dist/utils/parseJsDoc').default; | ||
const recast = require('recast'); | ||
|
||
const { types: { namedTypes: types } } = recast; | ||
// component-prop-types-js-doc-handler | ||
function componentPropTypesJsDocHandler(documentation, path) { | ||
let propTypesPath = getMemberValuePath(path, 'propTypes'); | ||
|
||
if (!propTypesPath) { | ||
return; | ||
} | ||
propTypesPath = resolveToValue(propTypesPath); | ||
if (!propTypesPath || !types.ObjectExpression.check(propTypesPath.node)) { | ||
return; | ||
} | ||
|
||
propTypesPath.get('properties').each((propertyPath) => { | ||
// we only support documentation of actual properties, not spread | ||
if (types.Property.check(propertyPath.node)) { | ||
const propName = getPropertyName(propertyPath); | ||
const propDescriptor = documentation.getPropDescriptor(propName); | ||
if (!propDescriptor.description || !propDescriptor.type) { | ||
return; | ||
} | ||
const jsDoc = parseJsDoc(propDescriptor.description); | ||
propDescriptor.description = jsDoc.description || propDescriptor.description; | ||
propDescriptor.type.params = jsDoc.params || []; | ||
propDescriptor.type.returns = jsDoc.returns; | ||
} | ||
}); | ||
} | ||
|
||
module.exports = componentPropTypesJsDocHandler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* eslint-disable */ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
/** | ||
* Component description. | ||
*/ | ||
export default class A extends React.Component { | ||
static propTypes = { | ||
optionalArray: PropTypes.array, | ||
requiredArray: PropTypes.array.isRequired, | ||
/** | ||
* Prop documentation | ||
*/ | ||
optionalBool: PropTypes.bool, | ||
requiredBool: PropTypes.bool.isRequired, | ||
optionalFunc: PropTypes.func, | ||
requiredFunc: PropTypes.func.isRequired, | ||
optionalNumber: PropTypes.number, | ||
requiredNumber: PropTypes.number.isRequired, | ||
optionalObject: PropTypes.object, | ||
requiredObject: PropTypes.object.isRequired, | ||
optionalString: PropTypes.string, | ||
requiredString: PropTypes.string.isRequired, | ||
optionalSymbol: PropTypes.symbol, | ||
requiredSymbol: PropTypes.symbol.isRequired, | ||
optionalNode: PropTypes.node, | ||
requiredNode: PropTypes.node.isRequired, | ||
optionalElement: PropTypes.element, | ||
requiredElement: PropTypes.element.isRequired, | ||
optionalMessage: PropTypes.instanceOf(Message), | ||
requiredMessage: PropTypes.instanceOf(Message).isRequired, | ||
optionalEnum: PropTypes.oneOf(['News', 'Photos']), | ||
requiredEnum: PropTypes.oneOf(['News', 'Photos']).isRequired, | ||
optionalUnion: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.number | ||
]), | ||
requiredUnion: PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.number | ||
]).isRequired, | ||
optionalArrayOf: PropTypes.arrayOf(PropTypes.number), | ||
requiredArrayOf: PropTypes.arrayOf(PropTypes.number).isRequired, | ||
optionalObjectOf: PropTypes.objectOf(PropTypes.number), | ||
requiredObjectOf: PropTypes.objectOf(PropTypes.number).isRequired, | ||
optionalAny: PropTypes.any, | ||
requiredAny: PropTypes.any.isRequired, | ||
optionalObjectWithShape: PropTypes.shape({ | ||
color: PropTypes.string, | ||
/** | ||
* Sub prop documentation | ||
*/ | ||
fontSize: PropTypes.number.isRequired, | ||
/** | ||
* @param {string} value | ||
*/ | ||
onChange: PropTypes.func, | ||
subShape: PropTypes.shape({ | ||
/** | ||
* Even deeper documentation | ||
*/ | ||
name: PropTypes.string, | ||
size: PropTypes.number | ||
}) | ||
}), | ||
/** | ||
* Callback with documentation | ||
* | ||
* @param {String} stringParam | ||
* @param {number} count | ||
* @param {React.MouseEvent} event | ||
* @param {React.KeyboardEvent} anotherEvent | ||
* @param {HTMLDivElement} element some html element | ||
* | ||
* @returns {string|number} | ||
*/ | ||
onClick: PropTypes.func, | ||
onChange: PropTypes.func | ||
}; | ||
|
||
render() { | ||
return null; | ||
} | ||
|
||
privateMethod(name) { | ||
} | ||
|
||
/** | ||
* Some description. | ||
* | ||
* @public | ||
*/ | ||
publicMethod1() { | ||
|
||
} | ||
|
||
/** | ||
* Maybe we just forgot to add params? | ||
* | ||
* @public | ||
*/ | ||
publicMethodWithouParams() { | ||
|
||
} | ||
|
||
/** | ||
* Some description. | ||
* | ||
* @public | ||
* @param {string} str1 Some description. | ||
* @param {String} str2 Some description. | ||
* @param {number} num1 Some description. | ||
* @param {Number} num2 Some description. | ||
* @param {Boolean} bool1 Some description. | ||
* @param {bool} bool2 Some description. | ||
* @param {boolean} bool3 Some description. | ||
* @param {string|number} union Some description. | ||
*/ | ||
publicWithParams(str1, str2, num1, num2, bool1, bool2, bool3, union) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`simple component with all prop types 1`] = ` | ||
" | ||
import { Component, ReactNode } from 'react'; | ||
import * as Type from 'prop-types'; | ||
|
||
export type AOptionalEnumFieldType = 'News' | 'Photos'; | ||
export type ARequiredEnumFieldType = 'News' | 'Photos'; | ||
export type AOptionalUnionFieldType = string | number; | ||
export type ARequiredUnionFieldType = string | number; | ||
export type AOptionalObjectOfFieldType = { | ||
readonly [key: string]: number; | ||
}; | ||
export type ARequiredObjectOfFieldType = { | ||
readonly [key: string]: number; | ||
}; | ||
export type AOptionalObjectWithShapeSubShapeFieldType = { | ||
|
||
/** | ||
* Even deeper documentation | ||
*/ | ||
readonly name?: string; | ||
readonly size?: number | ||
}; | ||
export type AOptionalObjectWithShapeFieldType = { | ||
readonly color?: string; | ||
|
||
/** | ||
* Sub prop documentation | ||
*/ | ||
readonly fontSize: number; | ||
|
||
/** | ||
* @param {string} value | ||
*/ | ||
readonly onChange?: Function; | ||
readonly subShape?: AOptionalObjectWithShapeSubShapeFieldType | ||
}; | ||
export type AOnClickReturnFieldType = string | number; | ||
export type APublicWithParamsUnionParamFieldType = string | number; | ||
|
||
|
||
export interface AProps { | ||
readonly optionalArray?: ReadonlyArray<any>; | ||
readonly requiredArray: ReadonlyArray<any>; | ||
|
||
/** | ||
* Prop documentation | ||
*/ | ||
readonly optionalBool?: boolean; | ||
readonly requiredBool: boolean; | ||
readonly optionalFunc?: Function; | ||
readonly requiredFunc: Function; | ||
readonly optionalNumber?: number; | ||
readonly requiredNumber: number; | ||
readonly optionalObject?: object; | ||
readonly requiredObject: object; | ||
readonly optionalString?: string; | ||
readonly requiredString: string; | ||
readonly optionalSymbol?: Symbol; | ||
readonly requiredSymbol: Symbol; | ||
readonly optionalNode?: ReactNode; | ||
readonly requiredNode: ReactNode; | ||
readonly optionalElement?: ReactNode; | ||
readonly requiredElement: ReactNode; | ||
readonly optionalMessage?: any/* Не нашёлся встроенный тип для типа {\\"name\\":\\"instanceOf\\",\\"value\\":\\"Message\\"} | ||
* https://github.com/alfa-laboratory/library-utils/issues/new | ||
*/; | ||
readonly requiredMessage: any/* Не нашёлся встроенный тип для типа {\\"name\\":\\"instanceOf\\",\\"value\\":\\"Message\\"} | ||
* https://github.com/alfa-laboratory/library-utils/issues/new | ||
*/; | ||
readonly optionalEnum?: AOptionalEnumFieldType; | ||
readonly requiredEnum: ARequiredEnumFieldType; | ||
readonly optionalUnion?: AOptionalUnionFieldType; | ||
readonly requiredUnion: ARequiredUnionFieldType; | ||
readonly optionalArrayOf?: ReadonlyArray<number>; | ||
readonly requiredArrayOf: ReadonlyArray<number>; | ||
readonly optionalObjectOf?: AOptionalObjectOfFieldType; | ||
readonly requiredObjectOf: ARequiredObjectOfFieldType; | ||
readonly optionalAny?: any; | ||
readonly requiredAny: any; | ||
readonly optionalObjectWithShape?: AOptionalObjectWithShapeFieldType; | ||
|
||
/** | ||
* Callback with documentation | ||
*/ | ||
readonly onClick?: (stringParam?: string, count?: number, event?: React.MouseEvent<any>, anotherEvent?: React.KeyboardEvent<any>, element?: HTMLDivElement) => AOnClickReturnFieldType; | ||
readonly onChange?: Function; | ||
|
||
} | ||
|
||
|
||
export type APropTypes = Record<keyof AProps, Type.Validator<AProps>>; | ||
|
||
|
||
/** | ||
* Component description. | ||
*/ | ||
|
||
export default class A extends Component<AProps> { | ||
static propTypes: APropTypes; | ||
|
||
/** | ||
* Some description. | ||
*/ | ||
publicMethod1(...args: any[]): any; | ||
|
||
/** | ||
* Maybe we just forgot to add params? | ||
*/ | ||
publicMethodWithouParams(...args: any[]): any; | ||
|
||
/** | ||
* Some description. | ||
*/ | ||
publicWithParams(str1?: string, str2?: string, num1?: number, num2?: number, bool1?: boolean, bool2?: boolean, bool3?: boolean, union?: APublicWithParamsUnionParamFieldType): void; | ||
} | ||
" | ||
`; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Heymdall
Если все поля readonly и поднята версия typescript - то не грех и generic утилитой Readonly воспользоваться чтоб читаемым было
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Или даже может стоить рискнуть и написать что-нибудь типа
type DeepReadonly = Readonly<{ [P in keyof T]: T[P] extends Array ? ReadonlyArray<DeepReadonly<T[P][0]>> : DeepReadonly<T[P]> }>;
Правда я думаю, что это еще не совсем корректно работает
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Было бы ништяк еслиб это работало
type DeepReadonly = T extends Array ? ReadonlyArray<DeepReadonly<T[0]>> : Readonly<{ [P in keyof T]: DeepReadonly<T[P]> }>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.typescriptlang.org/play/index.html#src=export%20type%20primitive%20%3D%20string%20%7C%20number%20%7C%20boolean%20%7C%20undefined%20%7C%20null%0D%0Aexport%20type%20DeepReadonly%3CT%3E%20%3D%0D%0A%20%20T%20extends%20primitive%20%3F%20T%20%3A%0D%0A%20%20T%20extends%20Array%3Cinfer%20U%3E%20%3F%20DeepReadonlyArray%3CU%3E%20%3A%0D%0A%20%20DeepReadonlyObject%3CT%3E%0D%0A%0D%0Aexport%20interface%20DeepReadonlyArray%3CT%3E%20extends%20ReadonlyArray%3CDeepReadonly%3CT%3E%3E%20%7B%7D%0D%0A%0D%0Aexport%20type%20DeepReadonlyObject%3CT%3E%20%3D%20%7B%0D%0A%20%20readonly%20%5BP%20in%20keyof%20T%5D%3A%20DeepReadonly%3CT%5BP%5D%3E%0D%0A%7D%0D%0Atype%20test%20%3D%20%7B%0D%0A%20%20%20%20a%3A%20number%3B%0D%0A%20%20%20%20b%3A%20Array%3C%7B%20c%3A%20number%3B%20d%3A%20Array%3C%7B%20e%20%7D%3E%7D%3E%0D%0A%7D%0D%0Atype%20o%20%3D%20DeepReadonlyObject%3Ctest%3E%3B%0D%0Avar%20t%3A%20o%3B%0D%0At.a%20%3D%20null%3B%0D%0At.b%20%3D%20null%3B%0D%0At.b%5B0%5D.c%20%3D%20null%3B%0D%0At.b%5B0%5D.d%5B0%5D.e%20%3D%20null%3B
@Heymdall Вот этой штукой попробуй обернуть пропс интерфейс.
Вроде работает. Нашел тут
microsoft/TypeScript#13923
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Heymdall, я тут подумал, что сам интерфейс компонента лучше не делать readonly. Потому что ты можешь ведь динамически набивать проемы, перед тем как передать их компоненту ( не всегда ты можешь хорошо стипизировать литерал). Поэтому важно чтобы только this.props было deepreadonly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Фишка в том, что там, где ожидается ридонли можно кинуть обычный, а наоборот - нет.
Ридонли же по сути сабсет обычных типов.
Начал приделывать это изначально именно из-за того что пришлось кастовать ридонли типы из редакс стейта до обычных, когда кидал их в наши компоненты.
Поэтому и захотелось сделать интерфейс компонента ридонли
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
А про DeepReadonly согласен, обновил